HttpServlet 踩坑问题¶
一、线程安全¶
HttpServlet 默认是单例,多线程共享。成员变量是非线程安全的:
public class MyServlet extends HttpServlet {
private int count = 0; // ❌ 所有请求共享
protected void doGet(...) {
count++;
}
}
解决:
- 不要用成员变量存请求状态。
- 用局部变量。
- 必须共享,用 AtomicInteger 或加锁。
二、响应已经提交¶
response.getWriter().write("hello");
// 业务出错
response.sendError(500); // IllegalStateException: response already committed
响应一旦 flush / close,再改 status 就报错。
三、中文乱码¶
request.setCharacterEncoding("UTF-8"); // 必须在 getParameter 前
response.setContentType("text/html;charset=UTF-8");
GET 请求中文乱码在 Tomcat 配置 URIEncoding="UTF-8"。
四、流只能读一次¶
request.getInputStream() 读完后,再 getParameter() 或再读流就读不到了。
解决:用 ContentCachingRequestWrapper(Spring)包装,或自定义 Filter 缓存 body。
五、异步处理¶
Servlet 3.0 支持异步:
@RequestMapping("/async")
public void asyncProcess() {
AsyncContext ctx = request.startAsync();
executor.execute(() -> {
// 处理
ctx.complete();
});
}
避免 Tomcat 线程被阻塞。
六、Spring MVC 之后¶
现代开发很少直接写 HttpServlet,都用 @Controller / @RestController。但理解底层仍重要。
七、常见问题¶
- 404:URL 映射错。
- 405:方法不支持(GET/POST 不匹配)。
- 500:业务异常。
- 响应乱码:编码没设对。
- 上传大小限制:
maxPostSize。
面试加分
- HttpServlet 单例多线程,成员变量线程不安全是高频考点。
- 现代 Spring Boot 自动配置了大部分 Servlet 细节。