我来自Node-ExpressJS,所以我熟悉中间件的概念。在学习Spring的过程中,我知道了一个名为Filter
的组件,该组件的行为与Express中的中间件类似,只是有一些区别。
因此,我试图了解Filter
和FilterChain
在Spring中的实际工作方式。
我有以下代码:
Filter1.java
@Component
@Order(1)
public class Filter1 implements Filter {
.....
.....
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
LOGGER.info("############# Invoking Filter1 ############");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
LOGGER.info("************ Moving on to next Filter");
LOGGER.info("Adding new Attribute");
req.setAttribute("Custom_Attribute_1", "TEST***TEST***TEST");
chain.doFilter(request, response);
resp.addHeader("1st Header", "1ST"); // Custom header that never shows up
LOGGER.info("+++++++++ GOING BACK FROM Filter1 +++++++++");
}
}
Filter2.java
@Component
@Order(2)
public class Filter2 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
LOGGER.info("############# Invoking Filter2 ####################");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
req.setAttribute("Filter2 Attribute", "2nd ORDER");
resp.addHeader("2nd Header", "2ND"); //Custom header that actually shows up
chain.doFilter(request, response);
LOGGER.info("+++++++++++ GOING BACK FROM Filter2 ++++++++++");
}
}
Controller.java
@RestController
public class Controller {
@GetMapping("/")
public ResponseEntity<Object> createResource(HttpServletRequest req) {
return new ResponseEntity<Object>("Resource Created",HttpStatus.OK);
}
}
当我使用Postman向控制器发送请求时,我只能在响应中看到我的一个自定义标头之一,即2nd Header
,但看不到另一个标头。
邮递员中的回复标题
2nd Header → 2ND
Content-Type → text/plain;charset=UTF-8
Content-Length → 15
Date → Thu, 19 Sep 2019 20:16:25 GMT
chain.doFilter(request, response)
的调用与此有关吗?似乎一旦调用response
的{{1}},就无法对Filter1
类中的doFilter
对象进行修改。
我想在这里理解的是:
如果需要调用FilterChain
来将FilterChain.doFilter
对象传播到下一个过滤器并最终传播到控制器,则不应允许request
对象response
的调用返回后会被修改吗?它内部如何工作?调用如何将所有信息传播到控制器,然后再返回到第一个过滤器?
此外,如果 Filter1 想要查看从 Filter2 返回的响应的正文并可能对其进行修改,它会如何做?
答案 0 :(得分:0)
基本上,doFilter()
将请求和响应对象发送到javadoc中提到的FilterChain中的下一个Filter。
在第一个示例中,在添加“第一个标头”之前,您将调用tha链中的下一个过滤器。这就是为什么您首先没有获得“ 1st Header”的原因。该请求将进入控制器层,然后由您的控制器进行评估。当控制器完成对对象的处理后,响应开始填充并返回到过滤器。
所以您的代码是这样的
arrived Filter1 -> Filter 2 > add "2st Header" > .. > Controller > Controller runs and prepares a response object.
Controller Response > .... > Filter 2 > Filter 1 > add "1st Header" > ...
因此,当请求到达您的控制器时,控制器在请求上下文中将永远不会有“ 1st Header”。
此外,如果Filter1希望在从Filter2返回并可以修改它之后看到响应的正文,那么它将如何处理?
我还没有尝试过,但是您应该看看this thread,它看起来像您想要实现的目标。