{"msg":"JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens\n at [Source: (PushbackInputStream); line: 1, column: 2]","code":500}
最近开发spring cloud的一个项目,项目中需要用到跨模块之间的调用,在开发的过程中,前期开发测试没有任何问题,代码开发完成时,在联调时出现了问题
具体描述如下:当参数过多时,会报{"msg":"JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\\r, \\n, \\t) is allowed between tokens\n at [Source: (PushbackInputStream); line: 1, column: 2]","code":500}这个错误
从网上找了很多办法,其中最为简单的是将compression.request.enabled = false,compression.response.enabled = false ,这样问题也能解决,但公司的架构师认为这样太粗暴,不够友好.....于是又找另外的解决方法
compression:
request:
enabled: true
# 配置压缩支持的 MIME TYPE
mime-types: text/xml,application/xml,application/json
# 配置压缩数据大小的下限
min-request-size: 2048
response:
enabled: true
第二种方法:将min-request-size: 2048的大小设置大一些。这个单位是b。也就是说,当参数小于这个压缩数据大小的下限时,会将传递的参数压缩,而在压缩的过程中,出现了乱码,另一个模块接收时报错了。将这个下限设置高,传递的参数可以更多,有点投机取巧的意思。不完美,在大佬的建议下,又找到第三种方法,如下:
# 配置压缩数据大小的下限
min-request-size: 2048
第三种方法:原有的配置不变,原来spring cloud模块之间的调用,他有自己原生的方法,不是okhttp,httpclient,具体的自己去查。在排查的过程中发现,httpclient的包没有引用到使用到的模块下,所以报错。所以需要引用如下包问题解决。
# feign 配置
feign:
sentinel:
enabled: true
okhttp:
enabled: false
httpclient:
enabled: true
client:
config:
default:
connectTimeout: 10000
readTimeout: 10000
<dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
第四种办法:将feign.okhttp.enabled = true,feign.httpclient.enabled = false
通过引用okhttp的方法,也能解决
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
增加拦截器动态删除Accept-Encoding 参数,使okhttp压缩生效
@Slf4j
public class HttpOkInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originRequest = chain.request();
Response response = null;
if (StringUtils.isNotEmpty(originRequest.header("Accept-Encoding"))) {
Request request = originRequest.newBuilder().removeHeader("Accept-Encoding").build();
long doTime = System.nanoTime();
response = chain.proceed(request);
long currentTime = System.nanoTime();
if(response != null) {
ResponseBody responseBody = response.peekBody(1024 * 1024);
LogUtil.info(log, String.format("接收响应: [%s] %n返回json:【%s】 %.1fms%n%s",
response.request().url(),
responseBody.string(),
(currentTime - doTime) / 1e6d,
response.headers()));
}else {
String encodedPath = originRequest.url().encodedPath();
LogUtil.info(log, String.format("接收响应: [%s] %n %.1fms%n",
encodedPath,
(currentTime - doTime) / 1e6d));
}
}
return response;
}
}
fegin配置类
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
//设置连接超时
.connectTimeout(10, TimeUnit.SECONDS)
//设置读超时
.readTimeout(10, TimeUnit.SECONDS)
//设置写超时
.writeTimeout(10, TimeUnit.SECONDS)
//是否自动重连
.retryOnConnectionFailure(true)
.connectionPool(new ConnectionPool(10, 5L, TimeUnit.MINUTES))
.build();
}
}
综上:上面的四种方法我都试过,都能成功,第一种比较暴力,推荐使用第三种,第四种,完美解决这个问题