Java过滤器无法设置响应标头

时间:2012-11-19 20:18:09

标签: java servlets http-headers request servlet-filters

我正在尝试创建一个Java“过滤器”来检测自定义HTTP请求标头,并插入响应标头以便文件自动下载。对此最重要的响应标头是“Content-Type = Attachment”响应标头。我创建了一个插入自定义标头的HTTP请求对象:

function myHttpObject(filePath){
function makeHttpObject() {
    return new XMLHttpRequest();
}

var request = makeHttpObject();

request.open("GET", filePath, false);
request.setRequestHeader("X-Wria-Download", "PDFdownload");
request.send(null);
window.open(filePath);
console.log(request.getAllResponseHeaders());
}

这会将X-Wria-Download标头插入请求中。 然后我有一个Java过滤器,它查找该请求标头,并应将响应标头设置为“Content-Type = attachment”

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Contenttypefilter implements Filter  {

protected FilterConfig filterConfig;

public void init(FilterConfig filterConfig) throws ServletException {
    this.filterConfig = filterConfig;
}

public void destroy() {
    //noop
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;

    //get the headers we placed in the request
    //based on those request headers, set some response headers

    if(req.getHeader("X-Wria-Download") != null){
        res.setHeader("Content-Type", "application/pdf");
        res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
    }

    chain.doFilter(req,res);
}


}

然后当然web.xml有代码在所有jsp文件中包含Filter。

令我感到困惑的是,标题是在响应文件上设置的,但它不是应该下载的。如果我把res.setHeader(“Content-Disposition”,“attachment; filename = success.pdf”);在“if”语句之外的行,然后它将工作,但它将下载行为应用于我不想要的所有JSP。

当我在if语句中使用res.setHeader时,为什么应用内容处理但不工作;然后在if语句之外工作?有关如何获得所需行为的任​​何想法(仅将内容处置应用于我已应用自定义请求标头的jsp)?

4 个答案:

答案 0 :(得分:11)

我认为您的问题与您的Web Context执行的过滤顺序有关,即您的网络上下文中的某些过滤器会在您的过滤器后执行并覆盖标题。

Servlet FilterChain of Responsibility模式

的实现

所以你可以尝试:

  • 在调用chain.doFilter后设置标题:

...

chain.doFilter(req,res);

HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;

//get the headers we placed in the request
//based on those request headers, set some response headers

if(req.getHeader("X-Wria-Download") != null){
    res.setHeader("Content-Type", "application/pdf");
    res.setHeader("Content-Disposition", "attachment; filename=success.pdf");
}

通过这种方式,您的代码将在调用Servlet之后执行,如下所述,如果您的过滤器是第一个在web.xml中声明的,那么setHeader代码将是最后执行的代码(请参阅图片如下)。

  • 确保您的过滤器是Servlet执行后最后执行的过滤器,即它应该是第一个声明为here的servlet过滤器:

enter image description here

正如您所看到的,Filter1(在web.xml中声明的第一个)是在执行servlet之前执行的第一个,以及在执行servlet之后执行的最后一个。因此,如果您想确保最后一个Filter设置标题,则将其声明为Filter1。

执行顺序由部署描述符(web.xml)中的声明顺序决定:

  

Servlet规范(第6.2.4节):

     

“容器用于构建过滤器链的顺序   申请特定请求的URI如下:

     

“1。首先,匹配的过滤器映射在同一个   命令这些元素出现在部署描述符中。

     

“2。接下来,匹配过滤器映射相同   命令这些元素出现在部署描述符中。“

因此,请务必将其声明为web.xml中的第一个过滤器。这样,它将是设置标题的最后一个过滤器。当然,如前所述,在调用chain.doFilter之后在代码中设置标题。

答案 1 :(得分:4)

假设您使用其他人所描述的响应包装器,那么整个秘密就是何时在原始响应上调用getWriter()!那是因为响应对象忽略了你要求作家后添加的所有标题!

因此,请确保在调用getWriter()之前添加所有标头。 这是我推荐的doFilter()序列:

  1. 创建响应包装器

  2. chain.doFilter(origRequest,wrapper);

  3. 将所有必需的标题分配给原始(!)响应

  4. 从原始回复中获取作家

  5. 将包装内容复制到此作者

答案 2 :(得分:0)

尝试此操作:如果请求标头存在,请在请求上设置属性。然后,在chain.doFilter(...)之后检查属性,然后设置响应头。

答案 3 :(得分:0)

问题是在提供过滤器之前,您的HttpServletRequest对象中没有设置AjaxRequest(此处为XMLHttpRequest)的标头(X-Wria-Download)。

我认为更好的想法是使用专用的Servlet来处理你的ajax请求