源码分析:Tomcat - 请求Header异步获取不到问题

前言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 为什么需要这个?
请求在结束时,header会清空,异步再从请求中获取header内容,就获取不到了。
org.apache.coyote.http11.Http11Processor.recycle --- inputBuffer.recycle();
org.apache.coyote.http11.Http11InputBuffer.recycle --- request.recycle();
org.apache.coyote.Request.recycle --- headers.recycle();
org.apache.tomcat.util.http.MimeHeaders.recycle

2. 大小写问题
解析转为小写 --- org.apache.coyote.http11.Http11InputBuffer.parseHeader
// chr is next byte of header name. Convert to lowercase.
if (chr >= Constants.A && chr <= Constants.Z) {
byteBuffer.put(pos, (byte) (chr - Constants.LC_OFFSET));
}
header 获取忽略大小写 --- org.apache.tomcat.util.http.MimeHeaders.getHeader

上下文-放入

省略其他代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Slf4j
@Order(2)
@Component
public class TokenFilter implements Filter {

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
ContextUtils.Header.init();

// [3] 执行下一个拦截器
filterChain.doFilter(servletRequest, servletResponse);
} finally {
ContextUtils.Header.remove();
}
}

}


public class AsyncUtils {
public static <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier) {
final LinkedCaseInsensitiveMap<String> header = ContextUtils.Header.get();

return CompletableFuture.supplyAsync(() -> {
try {
ContextUtils.Header.set(header);
return supplier.get();
} finally {
ContextUtils.Header.remove();
}
}, executor);
}
}

上下文-获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserUtil {

private static String header(String key) {
return Opt.ofTry(() -> ContextUtils.Header.get().get(key)).get();
}

// ios/android/h5
public static String platform() {
return header("platform");
}

// 设备ID
public static String deviceId() {
return header("deviceId");
}

public static String userAgent() {
return header("User-Agent");
}
}

上下文-定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ContextUtils {

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 请求header ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
public static class Header {

private static ThreadLocal<LinkedCaseInsensitiveMap<String>> header = ThreadLocal.withInitial(LinkedCaseInsensitiveMap::new);

public static void init() {
LinkedCaseInsensitiveMap<String> value = Header.get();
UserUtil.request().getHeaderNames().asIterator().forEachRemaining(key -> {
value.put(key, UserUtil.request().getHeader(key));
});

Header.header.set(value);
}

public static void set(LinkedCaseInsensitiveMap<String> value) {
header.set(value);
}

public static LinkedCaseInsensitiveMap<String> get() {
return header.get();
}

public static void remove() {
header.remove();
}
}

}