11

我正在尝试创建一个 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 文件中包含过滤器的代码。

令我困惑的是,响应文件上设置了标头,但它没有按应有的方式下载。如果我把 res.setHeader("Content-Disposition", "attachment; filename=success.pdf"); 在“if”语句之外的行,那么它将起作用,但它将下载行为应用于我不想要的所有 JSP。

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

4

4 回答 4

12

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

Servlet过滤器是责任链模式的一种实现

所以你可以尝试:

  • 在调用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 执行后最后执行的,即它应该是第一个声明的 servlet 过滤器,如下所述

在此处输入图像描述

如您所见,Filter1(web.xml 中的第一个声明)是在 servlet 执行之前执行的第一个,也是在 servlet 执行之后执行的最后一个。因此,如果您想确保成为最后一个设置标头的过滤器,则将其声明为 Filter1。

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

Servlet 规范(第 6.2.4 节):

“容器在构建要应用于特定请求 URI 的过滤器链时使用的顺序如下:

"1. 首先,匹配过滤器映射的顺序与这些元素在部署描述符中出现的顺序相同。

“2. 接下来,匹配过滤器映射的顺序与这些元素在部署描述符中出现的顺序相同。”

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

于 2012-11-20T22:09:14.037 回答
5

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

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

  1. 创建响应包装器

  2. chain.doFilter (origRequest, 包装器);

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

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

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

于 2017-09-06T05:33:08.443 回答
0

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

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

于 2012-11-20T04:16:45.580 回答
0

试试这个:如果请求标头存在,则在请求上设置一个属性。然后,检查 之后的属性chain.doFilter(...)并设置响应头。

于 2012-11-19T21:57:28.833 回答