过滤器看起来就是 doFilter 前后各写点代码,但顺序、短路、响应是否已提交、派发类型与异步都有细节。这篇用真实的容器把每一个都跑出来。
[order]
启动时:
A(/*).init()
B(/app/*).init()
C(精确 /app/x).init()
D(/other).init()
E(*.txt).init()
GET /app/x:200 “hello from hello” Content-Length=16
事件:
A(/*) 前(REQUEST /app/x)
B(/app/*) 前(REQUEST /app/x)
C(精确 /app/x) 前(REQUEST /app/x)
servlet hello 处理 /app/x 的 REQUEST
C(精确 /app/x) 后
B(/app/*) 后
A(/*) 后
GET /app/y:200 “hello from hello” Content-Length=16
事件:
A(/*) 前(REQUEST /app/y)
B(/app/*) 前(REQUEST /app/y)
servlet hello 处理 /app/y 的 REQUEST
B(/app/*) 后
A(/*) 后
GET /other:200 “hello from other” Content-Length=16
事件:
A(/*) 前(REQUEST /other)
D(/other) 前(REQUEST /other)
servlet other 处理 /other 的 REQUEST
D(/other) 后
A(/*) 后
GET /nothing.txt(没有 servlet 匹配,只有 *.txt 的过滤器):404 “<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/> <ti…” Content-Length=425
事件:
A(/*) 前(REQUEST /nothing.txt)
E(*.txt) 前(REQUEST /nothing.txt)
E(*.txt) 后
A(/*) 后
停止时:
E(*.txt).destroy()
D(/other).destroy()
C(精确 /app/x).destroy()
B(/app/*).destroy()
A(/*).destroy()
声明顺序对调(精确匹配的 X 先声明,通配的 Y 后声明)GET /app/x:200 “hello from hello” Content-Length=16
事件:
X(精确 /app/x,先声明) 前(REQUEST /app/x)
Y(/*,后声明) 前(REQUEST /app/x)
servlet hello 处理 /app/x 的 REQUEST
Y(/*,后声明) 后
X(精确 /app/x,先声明) 后 [short]
没有 token:401 “<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/> <ti…” Content-Length=418
事件:
auth 前
auth:没有 token,不调用 chain.doFilter
带 token:200 “hello from hello” Content-Length=16
事件:
auth 前
servlet hello 处理 /x 的 REQUEST
auth 后
过滤器既不调用 chain.doFilter 也不写响应:200 “” Content-Length=0
事件:
filter:没有调用 chain.doFilter,也没有写响应
过滤器调用 chain.doFilter 两次:200 “hello from hellohello from hello” Content-Length=32
事件:
filter:调用 chain.doFilter 两次
servlet hello 处理 /x 的 REQUEST
servlet hello 处理 /x 的 REQUEST
第二次 chain.doFilter 没有抛异常 [wrap]
请求包装(改参数 / 头 / URI):200 “name=AMY;ua=FAKE-UA;path=/p(wrapped);len=-1” Content-Length=43
响应包装(捕获 servlet 输出再改写):200 “HELLO FROM HELLO+EXTRA” X-Test=wrapped Content-Length=22
事件:
servlet hello 处理 /x 的 REQUEST
捕获到 16 字节,改写后 22 字符;写回之前 isCommitted = false
过滤器在 chain.doFilter 之后改状态码 / 头(响应小,可能已提交):状态 500;X-Late = 1;body “hello from hello”
事件:
servlet hello 处理 /x 的 REQUEST
servlet 返回之后 isCommitted = false;再 setHeader("X-Late")
再 setStatus(500) 之后 getStatus = 500
大响应(20 万字符,响应已提交):状态 200;X-Late = (没有);body 长度 200000
事件:
大响应 servlet 返回之后 isCommitted = true
再 setStatus(500) 之后 getStatus = 200 [dispatch]
GET /go?to=none:200 “plain” Content-Length=5
事件:
REQ-only 前(REQUEST /go)
fwd servlet(REQUEST)
REQ-only 后
GET /go?to=forward:200 “hello from target” Content-Length=17
事件:
REQ-only 前(REQUEST /go)
fwd servlet(REQUEST)
FORWARD-only 前(FORWARD /target)
servlet target 处理 /target 的 FORWARD
FORWARD-only 后
REQ-only 后
GET /go?to=include:200 “[outer]hello from target” Content-Length=24
事件:
REQ-only 前(REQUEST /go)
fwd servlet(REQUEST)
INCLUDE-only 前(INCLUDE /go)
servlet target 处理 /go 的 INCLUDE
INCLUDE-only 后
REQ-only 后
GET /go?to=error:404 “error page” Content-Length=10
事件:
REQ-only 前(REQUEST /go)
fwd servlet(REQUEST)
REQ-only 后
ERROR-only 前(ERROR /errpage)
error 页面 servlet(ERROR)
ERROR-only 后
GET /go?to=throw:500 “error page” Content-Length=10
事件:
REQ-only 前(REQUEST /go)
fwd servlet(REQUEST)
REQ-only 后
ERROR-only 前(ERROR /errpage)
error 页面 servlet(ERROR)
ERROR-only 后 [errors]
servlet 抛异常,有个过滤器捕获并改写:503 “handled by filter” Content-Length=17
事件:
outer 前(REQUEST /boom)
servlet 抛 IllegalStateException
catching 过滤器捕获 servlet 出错,改写成 503
outer 后
过滤器自己抛 ServletException:500 “ <ti…” Content-Length=519
事件:
outer 前(REQUEST /bad)
failing 过滤器抛 ServletException
outer 后
没人捕获时 servlet 抛异常:500 “ <ti…” Content-Length=520
事件(outer 的 finally 仍然执行):
outer 前(REQUEST /boom)
outer 后 [async]
异步请求:200 “async done” Content-Length=10;客户端实际耗时 361 ms
事件:
timer 过滤器 前
servlet startAsync
timer 过滤器 后(isAsyncStarted = true,经过 0 ms——测的不是整个请求)
异步线程 complete() [线程 async-pool][cost] 0 个空过滤器:每个请求中位数 67.7 µs(最小 66.8,最大 78.6;本机回环,串行请求,7 轮交错测量) 1 个空过滤器:每个请求中位数 67.5 µs(最小 66.9,最大 75.9;本机回环,串行请求,7 轮交错测量) 5 个空过滤器:每个请求中位数 67.3 µs(最小 66.9,最大 72.6;本机回环,串行请求,7 轮交错测量) 20 个空过滤器:每个请求中位数 67.2 µs(最小 66.8,最大 69.0;本机回环,串行请求,7 轮交错测量)