我需要根据页面内容修改此标题。
eg:这是一个人为的例子——因为它是被要求的。我无法详细了解特定标头的详细信息 servlet/页面根据访问的后端系统设置标头specialheader=xyz。如果设置了此特殊标头,过滤器会将其修改为 xyz+abc。如果未设置标头,过滤器会将其设置为 123。
我可以使用过滤器创建一个包装的
HttpServletResponse
并在返回时对其进行修改。不过,我对细节很模糊。
我知道在我的过滤器完成工作之前我必须防止输出被发送回客户端。为了做到这一点,我需要传递我自己的
OutputStream
并缓冲输出吗?
我真的需要这样做吗?我可以避免缓冲输出,这可能会给服务器带来负载
基本问题是 - 如果我需要在 doFilter 调用之后修改标头,我至少需要做什么? 是否有其他方法可以防止输出被提交,例如过度刷新等?
只需实现 getHeader 和 getHeaderNames 来忽略要丢弃的标头并将 Wrapper 设置为过滤器。
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Collection;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class GenericResponseWrapper extends HttpServletResponseWrapper {
public GenericResponseWrapper(final HttpServletResponse response) {
super(response);
}
@Override
public String getHeader(String name) {
// TODO Auto-generated method stub
return super.getHeader(name);
}
@Override
public Collection<String> getHeaderNames() {
// TODO Auto-generated method stub
return super.getHeaderNames();
}
}
public class Wrapper implements Filter {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final HttpServletResponse httpResponse = (HttpServletResponse) response;
final GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
wrapper.getResponse().setCharacterEncoding("UTF-8");
chain.doFilter(request, wrapper);
}
}
每当我搜索“如何修改已设置的 servlet 响应中的标头”时,这篇文章都会排在第一位,即使问题描述不同,我(也许像许多其他人一样)想知道如何修改 servlet 响应中的标头这是已经设定的。在这方面,我想为那些正在寻找的人发布我的答案(而不是写问题/答案)。
public class SameSiteCookieHeaderFilter implements Filter {
private static final String LOCALE_ID_COOKIE = "locale";
private static final String SET_COOKIE_HEADER = "Set-Cookie";
@Override
public void destroy() {
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
final HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
final Collection<String> setCookieHeaders = httpServletResponse.getHeaders(SET_COOKIE_HEADER);
for (final String setCookieHeader : setCookieHeaders) {
httpServletResponse.addHeader(SET_COOKIE_HEADER, setCookieHeader + "; Secure; SameSite=None");
}
if (setCookieHeaders.size() == 0) {
final Cookie[] cookies = httpServletRequest.getCookies();
for (final Cookie cookie : cookies) {
if (cookie.getName().equals(LOCALE_ID_COOKIE)) {
httpServletResponse.addHeader(SET_COOKIE_HEADER, buildSessionIdCookie(cookie.getValue()));
}
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
private String buildSessionIdCookie(final String value) {
return LOCALE_ID_COOKIE + "=" + value + "; " + "Path=/; " + "SameSite=None; " + "Secure; HttpOnly;";
}
web.xml
<filter>
<filter-name>SameSiteCookieHeaderFilter</filter-name>
<filter-class>de.chemmedia.kw.core.filter.SameSiteCookieHeaderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SameSiteCookieHeaderFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
所以它的作用是,它检测
Set-Cookie
标头并添加 SameSite=None
属性,或者采用 Cookie 并在每个响应中使用 Set-Cookie
构造 SameSite=None
。这样,就会有两个 Set-Cookie
标头具有相同的值,第二个标头将覆盖前一个标头,**或修改响应中已经存在的标头。
Set-Cookie: locale=EN; Path=/; HttpOnly;
Set-Cookie: locale=EN; Path=/; SameSite=None; Secure; HttpOnly;
仅供参考:tomcat 7.0.104、Servlet 3.1 和 Spring 4.2.x
您可以通过重写 HttpServletRequestWrapper 的 getHeader 方法来执行如下操作。
@Override
public Enumeration<String> getHeaders(String name) {
List<String> values = Collections.list(super.getHeaders(name));
if (headerMap.containsKey(name)) {
if (name.equals("Header_attibutes_needs_to_be_replace")) {
values.clear();
}
values.add(headerMap.get(name));
}
return Collections.enumeration(values);
}
在过滤器内设置新值
wrappedRequest = new HeaderMapRequestWrapper(request);
wrappedRequest.addHeader("Header_attibutes_needs_to_be_replace", value);
我发现自己必须使用“重置”方法来清除响应。 然后从头开始重新应用更改。
Map<String, Collection<String>> originalHeaders = readHeaders(response);
response.reset(); // Removes all the headers
// at this point you can add your own headers here
response.addHeader("Set-Cookie", "MyCookie=val");
// finally, put back all the headers except the ones you want.
// in this case I am replacing the Set-Cookie header so I skip that one
originalHeaders.forEach((headerName, headerValues) -> {
if (!headerName.equalsIgnoreCase("Set-Cookie")) {
headerValues.forEach(headerValue -> response.addHeader(headerName, headerValue));
}
});
我现在用新的 cookie 替换了 cookie。