问题
下面是通过filter对响应内容添加允许跨域响应头的代码,但是发现当响应内容过多时会出现添加的响应头部消失不见的问题,导致跨域失败。
@WebFilter(filterName = "h5CrossOriginFilter", urlPatterns = {"/h5/*"})
public class H5CrossOriginFilter extends BaseFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (httpRequest.getMethod().equals("OPTIONS")) {
ResponseUtil.outputText("允许跨域", httpResponse);
} else {
chain.doFilter(request, response);
}
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
}
}
原因
只能查一下源码了,httpResponse.setHeader()进去是这个样子,如下所示, isCommitted()为true,表示响应已经将数据发送到服务端,所以已经无法再设置响应头部,直接返回了。且出现这种情况的时候都是http分块传输。
根据猜测和以往的经验得出结论:在http进入filter时,就已经将所有要响应的数据放入到http响应流中了,在http协议发现响应数据超过上限时,便会先发送部分内容以清空响应流缓存,然后再接受剩余的要写入响应流的数据,同时触发http分块传输,所以在线程从web层返回到filter时,就无法再设置响应头了,因为响应头已经跟着分块传输的数据到客户端了。在传输文件的响应中,这种情况更加明显,甚至线程可以在web层中不出来,边生成数据边向客户端传递数据。
@Override
public void setHeader(String name, String value) {
if (isCommitted()) {
return;
}
response.setHeader(name, value);
}
解决方案
不要在filter中设置响应头,而要在web层中,直接获取响应对象,在写入响应数据前,便将响应头部设置好。这里图省事,直接添加了springframework的跨域标注,如果要添加其他响应头部,可以直接百度搜索web层获取响应对象,网上有很多办法。
@CrossOrigin // 跨域标注
@Controller
@RequestMapping("/h5")
public class H5Action extends ProtocolJsonController {
}
版权声明:本文为weixin_44927769原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。