引言
在Java Web开发中,HttpServletRequest是处理HTTP请求的核心接口。它封装了客户端发送给服务器的所有请求信息,是Servlet API中最重要的组件之一。无论您是初学者还是有经验的开发者,深入理解HttpServletRequest都是构建健壮Web应用的基础。
什么是HttpServletRequest?
HttpServletRequest是javax.servlet.http包中的一个接口,它继承自ServletRequest接口。当客户端(通常是浏览器)向服务器发送HTTP请求时,Web容器(如Tomcat、Jetty等)会创建一个HttpServletRequest对象,将所有请求信息封装在其中。
核心特性
- 封装HTTP请求的所有信息(请求行、请求头、请求体)
- 提供访问请求参数、属性和会话的方法
- 支持国际化和本地化
- 提供安全相关的方法
- 线程安全(每个请求都有独立的实例)
HttpServletRequest的主要功能
1. 请求基本信息获取
java
@WebServlet("/info")
public class RequestInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取请求方法
String method = request.getMethod();
// 获取请求URI和URL
String requestURI = request.getRequestURI();
StringBuffer requestURL = request.getRequestURL();
// 获取协议信息
String protocol = request.getProtocol();
String scheme = request.getScheme();
// 获取服务器信息
String serverName = request.getServerName();
int serverPort = request.getServerPort();
// 获取客户端信息
String remoteAddr = request.getRemoteAddr();
String remoteHost = request.getRemoteHost();
// 构造响应
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>请求信息详情</h2>");
out.println("<p>请求方法: " + method + "</p>");
out.println("<p>请求URI: " + requestURI + "</p>");
out.println("<p>请求URL: " + requestURL + "</p>");
out.println("<p>协议: " + protocol + "</p>");
out.println("<p>客户端地址: " + remoteAddr + "</p>");
}
}
2. 请求参数处理
HttpServletRequest提供了多种方式来获取请求参数:
java
@WebServlet("/params")
public class ParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置请求编码,防止中文乱码
request.setCharacterEncoding("UTF-8");
// 获取单个参数
String username = request.getParameter("username");
String age = request.getParameter("age");
// 获取多值参数(如复选框)
String[] hobbies = request.getParameterValues("hobbies");
// 获取所有参数名
Enumeration<String> paramNames = request.getParameterNames();
// 获取参数映射
Map<String, String[]> paramMap = request.getParameterMap();
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>参数处理结果</h2>");
out.println("<p>用户名: " + username + "</p>");
out.println("<p>年龄: " + age + "</p>");
if (hobbies != null) {
out.println("<p>爱好: " + String.join(", ", hobbies) + "</p>");
}
// 遍历所有参数
out.println("<h3>所有参数:</h3>");
for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
out.println("<p>" + entry.getKey() + ": " +
Arrays.toString(entry.getValue()) + "</p>");
}
}
}
3. 请求头操作
java
@WebServlet("/headers")
public class HeaderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取特定请求头
String userAgent = request.getHeader("User-Agent");
String accept = request.getHeader("Accept");
String host = request.getHeader("Host");
// 获取所有请求头名称
Enumeration<String> headerNames = request.getHeaderNames();
// 获取多值请求头
Enumeration<String> acceptEncodings = request.getHeaders("Accept-Encoding");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>请求头信息</h2>");
out.println("<p>User-Agent: " + userAgent + "</p>");
out.println("<p>Accept: " + accept + "</p>");
out.println("<p>Host: " + host + "</p>");
out.println("<h3>所有请求头:</h3>");
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
out.println("<p>" + headerName + ": " + headerValue + "</p>");
}
}
}
4. 会话管理
java
@WebServlet("/session")
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取当前会话,如果不存在则创建新会话
HttpSession session = request.getSession();
// 获取会话,但不创建新会话
HttpSession existingSession = request.getSession(false);
// 会话操作
String sessionId = session.getId();
long creationTime = session.getCreationTime();
long lastAccessedTime = session.getLastAccessedTime();
int maxInactiveInterval = session.getMaxInactiveInterval();
// 存储和获取会话属性
Integer visitCount = (Integer) session.getAttribute("visitCount");
if (visitCount == null) {
visitCount = 0;
}
visitCount++;
session.setAttribute("visitCount", visitCount);
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>会话信息</h2>");
out.println("<p>会话ID: " + sessionId + "</p>");
out.println("<p>创建时间: " + new Date(creationTime) + "</p>");
out.println("<p>最后访问时间: " + new Date(lastAccessedTime) + "</p>");
out.println("<p>访问次数: " + visitCount + "</p>");
}
}
5. 请求属性管理
java
@WebServlet("/attributes")
public class AttributeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置请求属性
request.setAttribute("currentTime", new Date());
request.setAttribute("userRole", "admin");
// 获取请求属性
Date currentTime = (Date) request.getAttribute("currentTime");
String userRole = (String) request.getAttribute("userRole");
// 获取所有属性名
Enumeration<String> attributeNames = request.getAttributeNames();
// 移除属性
// request.removeAttribute("userRole");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>请求属性</h2>");
out.println("<p>当前时间: " + currentTime + "</p>");
out.println("<p>用户角色: " + userRole + "</p>");
out.println("<h3>所有属性:</h3>");
while (attributeNames.hasMoreElements()) {
String attrName = attributeNames.nextElement();
Object attrValue = request.getAttribute(attrName);
out.println("<p>" + attrName + ": " + attrValue + "</p>");
}
}
}
高级特性和实践
1. 请求转发和包含
java
@WebServlet("/forward")
public class ForwardServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置转发数据
request.setAttribute("message", "这是转发的数据");
// 请求转发
RequestDispatcher dispatcher = request.getRequestDispatcher("/target");
dispatcher.forward(request, response);
// 或者包含其他资源
// dispatcher.include(request, response);
}
}
2. 文件上传处理
java
@WebServlet("/upload")
@MultipartConfig(
maxFileSize = 1024 * 1024 * 10, // 10MB
maxRequestSize = 1024 * 1024 * 50, // 50MB
fileSizeThreshold = 1024 * 1024 // 1MB
)
public class FileUploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取上传的文件
Part filePart = request.getPart("file");
if (filePart != null) {
String fileName = getFileName(filePart);
String uploadPath = getServletContext().getRealPath("/uploads");
// 确保上传目录存在
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}
// 保存文件
String filePath = uploadPath + File.separator + fileName;
filePart.write(filePath);
response.getWriter().println("文件上传成功: " + fileName);
}
}
private String getFileName(Part part) {
String contentDisposition = part.getHeader("content-disposition");
String[] tokens = contentDisposition.split(";");
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
return token.substring(token.indexOf('=') + 2, token.length() - 1);
}
}
return "";
}
}
3. 安全性考虑
java
@WebServlet("/secure")
public class SecurityServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 检查是否为HTTPS连接
boolean isSecure = request.isSecure();
// 获取认证信息
String authType = request.getAuthType();
String remoteUser = request.getRemoteUser();
Principal userPrincipal = request.getUserPrincipal();
// 角色检查
boolean isAdmin = request.isUserInRole("admin");
boolean isUser = request.isUserInRole("user");
// 输入验证和清理
String userInput = request.getParameter("input");
if (userInput != null) {
// 防止XSS攻击
userInput = escapeHtml(userInput);
}
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h2>安全信息</h2>");
out.println("<p>安全连接: " + isSecure + "</p>");
out.println("<p>认证类型: " + authType + "</p>");
out.println("<p>远程用户: " + remoteUser + "</p>");
out.println("<p>是否为管理员: " + isAdmin + "</p>");
}
private String escapeHtml(String input) {
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
}
常见问题和解决方案
1. 中文乱码问题
java
// 在Servlet开始处理之前设置编码
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 或者使用过滤器统一处理
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
2. 获取真实IP地址
java
public String getRealIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
3. 参数验证工具类
java
public class RequestValidator {
public static boolean isValidEmail(String email) {
String emailRegex = "^[A-Za-z0-9+_.-]+@(.+)$";
Pattern pattern = Pattern.compile(emailRegex);
return email != null && pattern.matcher(email).matches();
}
public static boolean isValidPhoneNumber(String phone) {
String phoneRegex = "^[1][3-9]\\d{9}$";
Pattern pattern = Pattern.compile(phoneRegex);
return phone != null && pattern.matcher(phone).matches();
}
public static String sanitizeInput(String input) {
if (input == null) return null;
return input.trim()
.replaceAll("<script[^>]*>.*?</script>", "")
.replaceAll("<[^>]+>", "");
}
public static Integer parseIntParameter(HttpServletRequest request,
String paramName, Integer defaultValue) {
String paramValue = request.getParameter(paramName);
if (paramValue == null || paramValue.trim().isEmpty()) {
return defaultValue;
}
try {
return Integer.parseInt(paramValue.trim());
} catch (NumberFormatException e) {
return defaultValue;
}
}
}
性能优化建议
1. 减少对象创建
java
// 避免在循环中创建不必要的对象
Map<String, String[]> paramMap = request.getParameterMap();
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
result.append(entry.getKey()).append("=")
.append(Arrays.toString(entry.getValue())).append("\n");
}
2. 合理使用请求属性
java
// 将计算结果存储在请求属性中,避免重复计算
String expensiveResult = (String) request.getAttribute("expensiveResult");
if (expensiveResult == null) {
expensiveResult = performExpensiveOperation();
request.setAttribute("expensiveResult", expensiveResult);
}
与Spring框架的集成
在Spring MVC中,HttpServletRequest的使用更加便捷:
java
@Controller
@RequestMapping("/spring")
public class SpringController {
@RequestMapping("/info")
public String getRequestInfo(HttpServletRequest request, Model model) {
// 直接注入HttpServletRequest
String userAgent = request.getHeader("User-Agent");
model.addAttribute("userAgent", userAgent);
return "info";
}
@RequestMapping("/param")
@ResponseBody
public Map<String, Object> handleParameters(
@RequestParam String name,
@RequestParam(defaultValue = "0") int age,
HttpServletRequest request) {
Map<String, Object> result = new HashMap<>();
result.put("name", name);
result.put("age", age);
result.put("remoteAddr", request.getRemoteAddr());
return result;
}
}