HeaderWriterFilter
介绍
HeaderWriterFilter是在请求前后写入一些往前请求头或者响应头写入一些信息,本身并不复杂。通过shouldWriteHeadersEagerly进行控制写入时机,shouldWriteHeadersEagerly为true时,写入操作在过滤链执行之前,否者过滤链执行完毕后再进行写入。shouldWriteHeadersEagerly默认为false,可以利用ObjectPostProcessor的机制(ObjectPostProcessor在系列文章会做讲解),设置为true。
HeaderWriterFilter写入的HeaderWriter笔者列举了一些,具体作用可以网上查阅:
- Header [name: X-Content-Type-Options, values: [nosniff]]
- Header [name: X-XSS-Protection, values: [1; mode=block]]
- Header [name: Cache-Control, values: [no-cache, no-store, max-age=0, must-revalidate]]
- Header [name: Pragma, values: [no-cache]]
- Header [name: Expires, values: [0]]
- 等等
代码分析
步骤1
HeaderWriterFilter的writeHeaders()方法写入了一组headerWriters,this.headerWriters是filter里的全局变量,this.headerWriters是由HeadersConfigurer配置的,HeaderWriterFilter和HeadersConfigurer的关键代码如下:
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.shouldWriteHeadersEagerly) {
doHeadersBefore(request, response, filterChain);
} else {
doHeadersAfter(request, response, filterChain);
}
}
private void doHeadersBefore(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
writeHeaders(request, response);
filterChain.doFilter(request, response);
}
private void doHeadersAfter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HeaderWriterResponse headerWriterResponse = new HeaderWriterResponse(request,
response);
HeaderWriterRequest headerWriterRequest = new HeaderWriterRequest(request,
headerWriterResponse);
try {
filterChain.doFilter(headerWriterRequest, headerWriterResponse);
} finally {
headerWriterResponse.writeHeaders();
}
}
void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
for (HeaderWriter writer : this.headerWriters) {
writer.writeHeaders(request, response);
}
}
private HeaderWriterFilter createHeaderWriterFilter() {
List<HeaderWriter> writers = getHeaderWriters();
if (writers.isEmpty()) {
throw new IllegalStateException(
"Headers security is enabled, but no headers will be added. Either add headers or disable headers security");
}
HeaderWriterFilter headersFilter = new HeaderWriterFilter(writers);
headersFilter = postProcess(headersFilter);
return headersFilter;
}
private List<HeaderWriter> getHeaderWriters() {
List<HeaderWriter> writers = new ArrayList<>();
addIfNotNull(writers, contentTypeOptions.writer);
addIfNotNull(writers, xssProtection.writer);
addIfNotNull(writers, cacheControl.writer);
addIfNotNull(writers, hsts.writer);
addIfNotNull(writers, frameOptions.writer);
addIfNotNull(writers, hpkp.writer);
addIfNotNull(writers, contentSecurityPolicy.writer);
addIfNotNull(writers, referrerPolicy.writer);
addIfNotNull(writers, featurePolicy.writer);
writers.addAll(headerWriters);
return writers;
}
private <T> void addIfNotNull(List<T> values, T value) {
if (value != null) {
values.add(value);
}
}
步骤2
HeaderWriterFilter有这样一个内部类,HeaderWriterResponse继承自OnCommittedResponseWrapper,它的onResponseCommitted()也会触发writeHeaders(),那么什么时候能回调用到onResponseCommitted(),在这个方法的代码段中打上一个断点,发现AbstractGenericHttpMessageConverter#write方法会最终触发doOnResponseCommitted(),猜测当Spring Mvc reponse的outputStream flush会触发doOnResponseCommitted(),截图和代码如下:
class HeaderWriterResponse extends OnCommittedResponseWrapper {
private final HttpServletRequest request;
HeaderWriterResponse(HttpServletRequest request, HttpServletResponse response) {
super(response);
this.request = request;
}
@Override
protected void onResponseCommitted() {
writeHeaders();
this.disableOnResponseCommitted();
}
protected void writeHeaders() {
if (isDisableOnResponseCommitted()) {
return;
}
HeaderWriterFilter.this.writeHeaders(this.request, getHttpResponse());
}
private HttpServletResponse getHttpResponse() {
return (HttpServletResponse) getResponse();
}
}