我正在尝试创建一个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)?
答案 0 :(得分:11)
我认为您的问题与您的Web Context
执行的过滤顺序有关,即您的网络上下文中的某些过滤器会在您的过滤器后执行并覆盖标题。
Servlet Filter是Chain of Responsibility模式
的实现所以你可以尝试:
...
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
代码将是最后执行的代码(请参阅图片如下)。
正如您所看到的,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()序列:
创建响应包装器
chain.doFilter(origRequest,wrapper);
将所有必需的标题分配给原始(!)响应
从原始回复中获取作家
将包装内容复制到此作者
答案 2 :(得分:0)
尝试此操作:如果请求标头存在,请在请求上设置属性。然后,在chain.doFilter(...)
之后检查属性,然后设置响应头。
答案 3 :(得分:0)
问题是在提供过滤器之前,您的HttpServletRequest对象中没有设置AjaxRequest(此处为XMLHttpRequest)的标头(X-Wria-Download)。
我认为更好的想法是使用专用的Servlet来处理你的ajax请求。