OKHttp3拦截器修改json请求体

发布于 27 天前  70 次阅读


最近需要在请求体而不是请求头中添加token校验,网上查找资料时碰到了一些预料之外的错误,于是记录下解决办法。

在okhttp3中添加拦截器时有两个方法:addInterceptor和addNetworkInterceptor,如果使用addNetworkInterceptor方法,那么网上的拦截器代码会发生错误。

原因是addNetworkInterceptor在发送请求时会自动添加一些请求头,包括:

  1. Connection:管理连接的持久性。
  2. Content-Length:表明请求体的长度。
  3. Host:指定请求的目标主机。
  4. User-Agent:标识客户端的类型和版本。

其中Content-Length限制了请求体的长度,如果在修改请求体的json时没有同时修改请求头的Content-Length的话,请求体会被截断报错或因长度不足报错,即使RequestBody会自动计算请求体的长度。

以下为拦截器类和测试类的代码:

//拦截器类
@Component
@Slf4j
public class BodyTokenInterceptor implements Interceptor {

    @NotNull
    @Override
    public Response intercept(okhttp3.Interceptor.Chain chain) throws IOException {

        // 获取原始请求
        Request originalRequest = chain.request();
        // 获取原始请求体
        RequestBody originalBody = originalRequest.body();
        MediaType mediaType = originalBody.contentType();
        Buffer buffer = new Buffer();
        originalBody.writeTo(buffer);
        String originalBodyString = buffer.readUtf8();

        // 修改请求体
        JSONObject jsonObject = JSONObject.parseObject(originalBodyString);
        jsonObject.put("auth", "token");

        RequestBody newBody = RequestBody.create(JSONObject.toJSONString(jsonObject), mediaType);
        Request newRequest = originalRequest.newBuilder()
            // 修改原请求体长度
            // .header("Content-Length", String.valueOf(newBody.contentLength()))
            .post(newBody)
            .build();

        // 继续处理修改后的请求
        return chain.proceed(newRequest);
    }
}

//测试控制器类
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @PostMapping("/send")
    public void send() {
        // 创建http客户端
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new BodyTokenInterceptor())
                // .addNetworkInterceptor(new BodyTokenInterceptor())
                .build();

        // 创建json请求体
        JSONObject json = new JSONObject();
        json.put("aaaa", "aaaaa");
        json.put("bbbb", "bbbbb");
        okhttp3.RequestBody body = okhttp3.RequestBody.create(json.toString(), MediaType.parse("application/json;charset=utf-8"));

        // 创建请求
        Request request = new Request.Builder()
                .url("http://localhost:8080/test/receive")
                .post(body)
                .build();

        try(Response response = client.newCall(request).execute()) {
            JSONObject jsonObject = JSONObject.parseObject(Objects.requireNonNull(response.body()).string());
            System.out.println(jsonObject);
        } catch (IOException e) {
            log.error(e.getMessage());
        }

    }

    @PostMapping("/receive")
    public void receive(@RequestBody HashMap<String,Object> body) {
        System.out.println(body);
    }
}