Spring 5 Reactive WebClient 添加请求及响应的interceptor
百度鹰眼返回的数据使用WebClient发送时不知道为什么是text/javascript类型的,所以想在webclient上添加一个拦截器,把response header的content-type修改成application/json。本来以为只是一个 函数调用的事,在stackoverflow上面也找到了类似的问题,但是答案中的class好像并不对头,所以花了很长时间才搞定,现在记录一下。大体思路就是拦截请求,然后检测返回的response的响应头是否有误,修改成application/json
。难点在于理清ClientHttpResponse、DefaultClientResponse、Headers、HttpHeaders等等乱七八糟的类,而且由于有些类或者字段不能访问,所以需要用反射来强行访问。
demo如下:
@Beanpublic WebClient yingyanClient() {
WebClient webClient = WebClient.builder().filter(modifyResponseHeader()) // 傻逼百度返回的content-type有时是text/javascript,需要修改成json.baseUrl("http://yingyan.baidu.com/api/v3").defaultHeader(HttpHeaders.USER_AGENT,"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36").build();return webClient;}private ExchangeFilterFunction modifyResponseHeader() {
// exchange可以理解为发送请求,返回一个ClientResponse的对象,它的默认实现类是DefaultClientResponse。DefaultClientResponse类中有一个字段代表了实际的响应,就是ClientHttpResponse类型的字段response,它的默认实现类型是ReactorClientHttpResponse,我们需要自定义一个类来代替它。然后我们用一个自定义的ClientResponseWrapper类来代替DefaultClientResponse。至于为什么需要同时修改两个类,那是因为使用bodyToMono或者bodyToFlux时在两个地方判断了Content-Type,一次使用了ClientResponse的方法,一次使用了ClientHttpResponse的方法。很晕=_=return