1. 概述
Web 应用程序主要基于请求-响应模型运作,这个模型描述了客户端与基于HTTP协议的Web服务器之间的数据交换。在服务器端,处理或拒绝请求时,理解发起请求的客户端至关重要。
在这个教程中,我们将学习如何从HTTP请求中获取客户端信息。
2. HTTP 请求对象
在了解HTTP请求之前,我们首先需要理解Servlet。Servlet是Java实现Web开发扩展能力的基础部分,用于处理HTTP请求并生成动态内容。
在Java Servlet API中,HttpServletRequest接口代表客户端发送的HTTP请求。HttpServletRequest
对象非常方便,可以用来捕获关于客户端的重要信息。HttpServletRequest
提供了现成的方法,如getRemoteAddr()
、getRemoteHost()
、getHeader()
和getRemoteUser()
,这些方法有助于提取客户端信息。
2.1. 获取客户端IP地址
我们可以使用getRemoteAddr()
方法获取客户端的IP地址:
String remoteAddr = request.getRemoteAddr(); // 198.167.0.1
需要注意的是,这个方法返回的是服务器看到的IP地址,可能并不总是代表真实的客户端IP,因为可能会受到代理服务器、负载均衡器等因素的影响。
2.2. 获取远程主机
我们可以使用getRemoteHost()
方法获取客户端的主机名:
String remoteHost = request.getRemoteHost(); // baeldung.com
2.3. 获取远程用户
如果客户端已认证,我们可以使用getRemoteUser()
方法获取用户名:
String remoteUser = request.getRemoteUser(); // baeldung
值得注意的是,如果客户端未认证,那么将得到null
。
2.4. 获取客户端头信息
我们可以使用getHeader(headerName)
方法读取客户端传递的头信息:
String contentType = request.getHeader("content-type"); // application/json
获取客户端信息的一个重要头信息是User-Agent
头。它包含了关于客户端软件、系统等的信息。一些关键信息可能包括浏览器类型、操作系统、设备信息、插件、扩展等。
以下是一个User-Agent
字符串的例子:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
我们可以使用HttpServletRequest
提供的getHeader(String headerName)
方法来读取User-Agent
头。由于User-Agent
字符串的动态性,解析起来可能较为复杂。然而,不同编程语言中有相应的库可以帮助处理。对于Java生态系统,一个流行的选择是uap-java库。
除了上述方法外,还有其他方法,如getSessionID()
、getMethod()
、getRequestURL()
等,具体取决于应用场景。
3. 提取客户端信息
如上一节所述,为了解析User-Agent
,我们可以使用uap-java库。为此,我们需要在pom.xml
文件中添加如下XML片段:
<dependency>
<groupId>com.github.ua-parser</groupId>
<artifactId>uap-java</artifactId>
<version>1.5.4</version>
</dependency>
配置好依赖后,我们可以创建一个简单的AccountServlet
,作为客户端的HTTP端点,并接收请求:
@WebServlet(name = "AccountServlet", urlPatterns = "/account")
public class AccountServlet extends HttpServlet {
public static final Logger log = LoggerFactory.getLogger(AccountServlet.class);
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
AccountLogic accountLogic = new AccountLogic();
Map<String, String> clientInfo = accountLogic.getClientInfo(request);
log.info("Request client info: {}, " + clientInfo);
response.setStatus(HttpServletResponse.SC_OK);
}
}
然后,我们可以将请求对象传递给AccountLogic
,它从用户请求中提取客户端信息。接着,我们可以创建一个AccountLogic
类,其中包含获取客户端信息的所有逻辑。我们可以使用前面讨论过的通用辅助方法:
public class AccountLogic {
public Map<String, String> getClientInfo(HttpServletRequest request) {
String remoteAddr = request.getRemoteAddr();
String remoteHost = request.getRemoteHost();
String remoteUser = request.getRemoteUser();
String contentType = request.getHeader("content-type");
String userAgent = request.getHeader("user-agent");
Parser uaParser = new Parser();
Client client = uaParser.parse(userAgent);
Map<String, String> clientInfo = new HashMap<>();
clientInfo.put("os_family", client.os.family);
clientInfo.put("device_family", client.device.family);
clientInfo.put("userAgent_family", client.userAgent.family);
clientInfo.put("remote_address", remoteAddr);
clientInfo.put("remote_host", remoteHost);
clientInfo.put("remote_user", remoteUser);
clientInfo.put("content_type", contentType);
return clientInfo;
}
}
最后,我们准备好编写一个简单的单元测试来验证功能:
@Test
void givenMockHttpServletRequestWithHeaders_whenGetClientInfo_thenReturnsUserAGentInfo() {
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
when(request.getHeader("user-agent")).thenReturn("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36, acceptLanguage:en-US,en;q=0.9");
when(request.getHeader("content-type")).thenReturn("application/json");
when(request.getRemoteAddr()).thenReturn("198.167.0.1");
when(request.getRemoteHost()).thenReturn("baeldung.com");
when(request.getRemoteUser()).thenReturn("baeldung");
AccountLogic accountLogic = new AccountLogic();
Map<String, String> clientInfo = accountLogic.getClientInfo(request);
assertThat(clientInfo.get("os_family")).isEqualTo("Mac OS X");
assertThat(clientInfo.get("device_family")).isEqualTo("Mac");
assertThat(clientInfo.get("userAgent_family")).isEqualTo("Chrome");
assertThat(clientInfo.get("content_type")).isEqualTo("application/json");
assertThat(clientInfo.get("remote_user")).isEqualTo("baeldung");
assertThat(clientInfo.get("remote_address")).isEqualTo("198.167.0.1");
assertThat(clientInfo.get("remote_host")).isEqualTo("baeldung.com");
}
4. 总结
在这篇文章中,我们了解了HttpServletRequest
对象,它提供了获取请求客户端信息的有用方法。我们还学习了User-Agent
头,它提供了关于浏览器家族、操作系统家族等系统级别的信息。
随后,我们实现了从请求对象中获取客户端信息的逻辑。
如往常一样,示例代码可在GitHub上找到。