之前我们配置过 zuul 作为 api 网关 《SpringCloud(Finchley.SR2版本)踩坑笔记(四)------- zuul基础》,zuul 还可以自定义一系列的过滤器,来对请求做一些预先或者后续的处理。
zuul 的 filter 类型分为:
1. pre:在请求被路由之前过滤,可以通过这种过滤器来处理一些类似签名校验,用户身份认证等操作。
2. route:这种过滤器用于构建发送给微服务的请求。
3. post:这种过滤器在微服务有返回结果时过滤,可以用来处理一些标准的 http header,记录返回值之类的操作。
4. error:顾名思义,在发成错误时触发的过滤器。
定义一个 Filter 需要继承 ZuulFilter
public class SignatureFilter extends ZuulFilter {
public SignatureFilter() {
// 构造函数
}
@Override
public String filterType() {
// 定义 filter 的类型
return FilterConstants.PRE_TYPE; // 可以在请求被路由之前调用
}
@Override
public int filterOrder() {
// filter 执行顺序,数字越小优先级越高
return 0;
}
@Override
public boolean shouldFilter() {
// 是否要被过滤,可以增加自己的业务逻辑判断最后返回 true or false
return true;
}
@Override
public Object run() {
// 过滤逻辑实现
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
return null;
}
}
这样一个自定义的 Filter 就完成了。
很多情况下,我们开发的微服务接口都需要做跨域请求的处理,在 zuul 中,可以通过自定义 Filter 的方式来解决,也可以通过如下方式来自定义一个config解决。
@Configuration
public class CorsConfig {
private final Logger LOGGER = LoggerFactory.getLogger(ZuulApplication.class);
@Bean
public CorsFilter corsFilter() {
LOGGER.info("zuul add cors config");
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
跨域请求中,关键是服务器将 response 设置 header ACCESS_CONTROL_ALLOW_ORIGIN 为正确的值,但是在上述配置的注释信息中可以得知,addAllowedOrigin("*") 在 springmvc 中会自动设置为 request header 的 origin,这时你可能在客户端的请求中发现 response.header 中的 ACCESS_CONTROL_ALLOW_ORIGIN 会有两个值,导致跨域请求在前端认为失败。原因是 zuul 又将这个 header 写了一遍,解决的方法是配置 zuul 的 sensitiveHeaders
zuul:
routes:
app-server:
path: /test-server/**
sensitiveHeaders: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
serviceId: test-server
stripPrefix: false
这样就能解决了,当然也可以直接配置 zuul.sensitiveHeaders 做全局配置。
sensitiveHeaders 的作用是将设置的 header 不向下层微服务传递。还有一个配置是 ignoredHeaders,这里面的 header 会向下层微服务传递,但是微服务再次转发的时候就不会有了。
另外 stripPrefix 的作用是影响传递到微服务的请求地址,比如一个请求:http://zuul-server/test-server/test,stripPrefix = false,那么微服务获得的地址就是 /test-server/test,如果为 true, 那么微服务获得地址就是 /test