网络请求
更新: 8/11/2025 字数: 0 字 时长: 0 分钟
参考文章
后端转发请求也是一个十分常见的需求,我们需要Java服务作为客户端调用远程的http/ws接口,然后再在内部进行处理,最后转发给前端,这里主要来讲一下进行网络请求常用的技术栈
OkHttp
OkHttp算是一个相当常见的客户端请求工具了,时至今日仍然是最受欢迎的客户端请求工具之一,其本身支持多种丰富的网络请求模式,其中就包含了我们常见的Http,WebSocket,SSE请求。
引入到项目中
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-jvm</artifactId>
<version>5.1.0</version>
</dependency>
由于新版本的OkHttp对KMP做了适配,因此在Maven项目中要针对不同的情况引入不同的包,针对我们目前的Java项目(后端jvm环境),这里引入okhttp-jvm
即可
ps:由于OkHttp最早是为Android做的请求包,而Google已经将Android的官方语言替换为了Kotlin,因此在我们的Java项目中引入OHttp会引入一些Kotlin标准库,这会对程序的内存占用造成一定的影响
建立连接
首先我们要先创建一个OkHttp客户端,后续我们的各种请求都是基于这个客户端。
OkHttpClient httpClient = new OkHttpClient.Builder()
.build();
这里使用了Builder模式进行创建,其实也可以通过new 的方式直接创建,但是如果要进行一些复杂的配置还是建议使用Builder模式
Get请求
这里推荐一个好用的HttpApi网站JSONPlaceholder,他提供了一些常见的Api服务,可以给客户端用来测试是否可以正常发送请求
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://jsonplaceholder.typicode.com/posts/1")
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
System.out.println(response.body().string());
} else {
System.err.println("Request failed: " + response.code());
}
} catch (IOException e) {
e.printStackTrace();
}
}
这里我们的Request请求是通过创建一个Request实体实现的,里面可以放我们的请求的url以及Parm
返回的Response类就是相应的信息,需要使用try-with-resource语法包围一下
发送带有参数的GET请求
常见的GET请求的参数在Param中,这里我们可以自己拼接请求连接,不过这样不够优雅,OkHttp为我们提供了拼接url连接的工具
OkHttpClient client = new OkHttpClient();
HttpUrl.Builder queryUrlBuilder = HttpUrl.get("https://mytodoserver.com/todolist").newBuilder();
queryUrlBuilder.addQueryParameter("filter", "done");
Request request = new Request.Builder()
.url(queryUrlBuilder.build())
.build();
try {
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
发送Post请求
针对Post请求OkHttp也有专门的处理方式
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("new", "This is my new TODO")
.build();
Request postRequest = new Request.Builder()
.url("https://mytodoserver.com/new")
.post(requestBody)
.build();
try {
Response response = client.newCall(postRequest).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
这里我们可以看到,使用了FormBody Builder来创建请求体,然后将请求体塞入Request的post方法中即可使用
或者传一个JSON
OkHttpClient client = new OkHttpClient();
JSONObject jsonObject = new JSONObject();
jsonObject.put("todo_id", 123);
jsonObject.put("status", "done");
RequestBody requestJsonBody = RequestBody.create(
jsonObject.toString(),
MediaType.parse("application/json")
); //这里是直接使用的RequestBody的Builder方法
Request postRequest = new Request.Builder()
.url("https://mytodoserver.com/modify")
.post(requestJsonBody)
.build();
try {
Response response = client.newCall(postRequest).execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
MultipartBody.Part
上面介绍了三种创建请求体的形式,JSON,FormBody(对应application/x-www-form-urlencoded
),那么对于表单数据应该使用那种呢?
这里就是我们的MultipartBody.Part,它提供了一种与multipart/form-data
对应的传输格式,用来将不同的k-v作为独立的数据块进行上传,这种方式适合我们传输文件与有自己的请求头(例如,Content-Disposition
)和请求体的数据。这使得每个 Part
都是一个完整、独立的数据单元,即使它们拥有相同的 name(或者说是key)
。
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
for (String path : paths) {//List<String> paths多个文件本地路径地址
File file = new File(path);
RequestBody requestBody = RequestBody.create(MediaType.parse("text/x-markdown; charset=utf-8"), file);
builder.addFormDataPart("files",file.getName(),requestBody);//files 文件上传参数
}
List<MultipartBody.Part> parts = builder.build().parts();
通过builder.addFormDataPart的方式去创建表单数据
当然,你也可以通过MultipartBody.Part.createFormData的方法创建MultipartBody.Part的实例对象,进而手动构建一个List<MultipartBody.Part>
WebSocket
OkHttp也提供了基于WebSocket的连接沟通
OkHttpClient client = new OkHttpClient();
String socketServerUrl = "ws://mytodoserver.com/realtime";
Request request = new Request.Builder().url(socketServerUrl).build();
// connecting to a socket and receiving messages
client.newWebSocket(request, new WebSocketListener() {
@Override
public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
super.onClosed(webSocket, code, reason);
//TODO: implement your own event handling
}
@Override
public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
super.onClosing(webSocket, code, reason);
//TODO: implement your own event handling
}
@Override
public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {
super.onFailure(webSocket, t, response);
//TODO: implement your own event handling
}
@Override
public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
super.onMessage(webSocket, text);
//TODO: implement your own event handling for incoming messages
}
@Override
public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {
super.onMessage(webSocket, bytes);
//TODO: implement your own event handling for incoming messages
}
@Override
public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
super.onOpen(webSocket, response);
//TODO: implement your own event handling
}
});
// sending message
webSocket.send("new_todo_added");
这里的重点在于这个WebSocketListener,这个是WebSocket的监听器,用来处理各种情况下要怎么做(回调函数)
OkHttpClient的newWebSocket参数会返回一个WebSocket实例,这个实例用来操作当前的WebSocket状态,内涵send,close等方法,用来主动的向对方发送信息
针对WebSocket类型的连接,OkHttpClient还专门设置了一个pingInterval(心跳)函数,其就是用来检测对方在多少时间内没有发送内容,如果超出这个时间对方没有主动的发送消息,则认为对方出现异常,会主动调用WebSocketListener中的onFailure方法
Retrofit
Retrofit是基于OkHttp再封装的一个包,其用来更加便捷的发送Http请求
Retrofit使用大量的注解来简化请求,也就是说我们只需要针对一个远程地址定义一个接口就可以直接进行沟通(类似mp或jpa的接口调用数据库)
Retrofit SpringBoot
Retrofit最开始是写给安卓客户端用的包,但是随着Java服务端调用远程服务的需求逐渐增加,SpringBoot+Retrofit的组合也逐渐变得平常了起来,对于这种场景我们可以使用贝壳开源的retrofit-spring-boot-starter(最新版强制要求Java17)