开发笔记
1. Jackson 配置不生效
程序中使用@EnableWebMvc时配置文件中有关Jackson的配置不会生效
As described in the documentation, when you use @EnableWebMvc you are indicating that you will take complete control over Spring MVC's configuration. That includes configuring how it uses Jackson to render responses
https://github.com/spring-projects/spring-boot/issues/9941
2. 下载文件中文名乱码以及指定文件编码类型以及文件大小
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename, "utf8"));
response.setContentLength(decode.length);
3. gateway 踩坑
1. 使用 feign 时需要自己装载 HttpMessageConverters
@Bean
public HttpMessageConverters httpMessageConverters(MyMappingJackson2HttpMessageConverter converter) {
return new HttpMessageConverters(converter);
}
@Bean
public Decoder feignDecoder(MyMappingJackson2HttpMessageConverter converter) {
ObjectFactory<HttpMessageConverters> factory = () -> new HttpMessageConverters(converter);
return new OptionalDecoder(
new ResponseEntityDecoder(new SpringDecoder(factory)));
}
@Bean
public MyMappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MyMappingJackson2HttpMessageConverter();
}
public static class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public MyMappingJackson2HttpMessageConverter() {
List<MediaType> mediaTypeList = new ArrayList<>(this.getSupportedMediaTypes());
mediaTypeList.add(MediaType.TEXT_PLAIN);
this.setSupportedMediaTypes(mediaTypeList);
}
}
2. gateway服务不能包含 tomcat 的依赖
3. filter 中调用 feign 会报错
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-N
原因是gateway 的 filter 是基于 webFlux 响应式的,而 feign 是同步的, 所以要把调用改成异步调用也就是 Future, 例如:
ExecutorService executorService = Executors.newCachedThreadPool();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (vionConfig.getAuthEnabled() && !skip(request)) {
String token = getToken(request);
if (token == null) {
return unAuthorized(exchange.getResponse(), "authorization failed");
}
// 鉴权
ImmutablePair<Boolean, String> checkResult = checkToken(token);
Boolean success = checkResult.left;
if (!success) {
log.info("token校验未通过:[{}][{}]", checkResult.right, request.getPath());
return unAuthorized(exchange.getResponse(), checkResult.right);
}
// 添加 username 到 header 中, 供之后的服务使用
ServerHttpRequest req = request.mutate().headers(headers -> headers.add("username", checkResult.right)).build();
exchange.mutate().request(req).build();
log.info("token 校验成功:{}", token);
}
return chain.filter(exchange);
}
private ImmutablePair<Boolean, String> checkToken(String token) {
// todo authorize
String username;
try {
Map<String, String> api = new HashMap<>(2);
api.put("verb", HttpMethod.POST.name());
api.put("path", "/api/v1/auth/authorize");
Map<String, Object> perm = new HashMap<>(2);
perm.put("type", "api");
perm.put("api", api);
// webFlux 是异步的,这里不能直接用 feign 调用
Future<JSONObject> perm1 = executorService.submit(() -> authClient.checkToken(token, Collections.singletonMap("perm", perm)));
JSONObject jsonObject = perm1.get();
username = jsonObject.getString("username");
} catch (Exception e) {
log.info("token 校验失败:", e);
return ImmutablePair.of(false, e.getLocalizedMessage());
}
return ImmutablePair.of(true, username);
}
也可以使用
CompletableFuture.supplyAsync()方法
4. Redisson LocalCachedMap
对于同一个缓存对象,LocalCachedMap创建一次即可,多次创建会导致内存泄漏