1. Overview
1.概述
Web applications mainly work on the request-response model, and this model describes data exchange between a client and a web server using HTTP protocol. At the server end, which accepts or denies requests, it’s very important to understand the client who is making that request.
Web应用程序主要基于请求-响应模型工作,该模型描述了客户端与Web服务器之间使用 HTTP 协议进行的数据交换。在接受或拒绝请求的服务器端,了解发出请求的客户端非常重要。
In this tutorial, we’ll learn how to capture client information from an HTTP request.
在本教程中,我们将学习如何从 HTTP 请求中捕获客户端信息。
2. HTTP Request Object
2.HTTP 请求对象
Before learning about HTTP requests, we should first understand Servlet. Servlet is a fundamental part of Java’s implementation to extend the the capability of web development in order to process the HTTP request and generate dynamic content in the response.
在学习 HTTP 请求之前,我们首先应该了解 Servlet 。Servlet是 Java 实现的一个基本部分,用于扩展 Web 开发能力,以处理 HTTP 请求并在响应中生成动态内容。
HttpServletRequest is an interface in Java Servlet API that represents HTTP requests made by clients. The HttpServletRequest object is very handy in capturing important information about clients. HttpServletRequest provides out-of-the-box methods such as getRemoteAddr(), getRemoteHost(), getHeader(), and getRemoteUser() which help in extracting client information.
HttpServletRequest 是 Java Servlet API 中的一个接口,用于表示客户端发出的 HTTP 请求。HttpServletRequest对象在捕获有关客户端的重要信息时非常方便。HttpServletRequest 提供了开箱即用的方法,如 getRemoteAddr()、getRemoteHost()、getHeader() 和 getRemoteUser(),这些方法有助于提取客户端信息。
2.1. Getting the Client IP Address
2.1.获取客户端 IP 地址
We can get the IP address of the client using the getRemoteAddr() method:
我们可以使用 getRemoteAddr() 方法获取客户端的 IP 地址:
String remoteAddr = request.getRemoteAddr(); // 198.167.0.1
It’s important to note that this method retrieves the IP address as seen by the server and might not always represent the true client IP address due to factors like proxy servers, load balancers, etc.
值得注意的是,这种方法检索的是服务器看到的 IP 地址,由于代理服务器、负载平衡器等因素,可能并不总是真实的客户端 IP 地址。
2.2. Getting the Remote Host
2.2.获取远程主机
We can get the hostname of the client using the getRemoteHost() method:
我们可以使用 getRemoteHost() 方法获取客户端的主机名:
String remoteHost = request.getRemoteHost(); // baeldung.com
2.3. Getting the Remote User
2.3.获取远程用户
We can get the client username, if it’s authenticated, using the getRemoteUser() method:
如果已通过身份验证,我们可以使用 getRemoteUser() 方法获取客户端用户名:
String remoteUser = request.getRemoteUser(); // baeldung
It’s important to note that if the client is not authenticated, then we might get null.
值得注意的是,如果客户端未通过身份验证,我们可能会得到 null 结果。
2.4. Getting Client Headers
2.4.获取客户端头信息
We can read header values passed by the client using the getHeader(headerName) method:
我们可以使用 getHeader(headerName) 方法读取客户端传递的头信息值:
String contentType = request.getHeader("content-type"); // application/json
One of the important headers for getting client information is the User-Agent header. It includes information such as the client’s software, system, etc. Some of the important information might include the browser, OS, device info, plugins, add-ons, etc.
获取客户端信息的重要header之一是User-Agent header。它包括客户端的软件、系统等信息。其中一些重要信息可能包括浏览器、操作系统、设备信息、插件、附加组件等。
Below is an example of a User-Agent string:
下面是 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
We can read the User-Agent header using the getHeader(String headerName) method provided by HttpServletRequest. Parsing the User-Agent string can be inherently complex due to its dynamic nature. However, there are libraries available in different programming languages that can ease this task. For the Java ecosystem, uap-java is a popular option.
我们可以使用 HttpServletRequest 提供的 getHeader(String headerName) 方法来读取 User-Agent 标头。由于 User-Agent 字符串的动态性质,解析 User-Agent 字符串本身就很复杂。不过,不同编程语言中都有可用的库来简化这项任务。对于 Java 生态系统,uap-java是一个常用的选项。
Apart from the above methods, there are other methods, such as getSessionID(), getMethod(), getRequestURL(), etc., that may be helpful depending on the use cases.
除上述方法外,还有 其他方法,例如 getSessionID()、getMethod()、getRequestURL() 等,根据使用情况,这些方法可能会有所帮助。
3. Extracting Client Information
3.提取客户信息
As discussed in the previous section, to parse User-Agent, we can use the uap-java library. For that, we need to add the below XML snippet inside the pom.xml file:
如上一节所述,要解析 User-Agent,我们可以使用 uap-java 库。为此,我们需要在 pom.xml 文件中添加以下 XML 代码段:
<dependency>
<groupId>com.github.ua-parser</groupId>
<artifactId>uap-java</artifactId>
<version>1.5.4</version>
</dependency>
Once we have the dependency configured, let’s create a simple AccountServlet, which acts as an HTTP endpoint for the client and accepts requests:
配置好依赖关系后,让我们创建一个简单的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);
}
}
Then, we can pass our request object to AccountLogic, which extracts client information from user requests. Then, we can create an AccountLogic class that mainly consists of all the logic for getting client information. We can use all the common helper methods that we discussed earlier:
然后,我们可以将请求对象传递给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;
}
}
Finally, we’re ready to write a simple unit test to verify the functionality:
最后,我们准备编写一个简单的单元测试来验证功能:
@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. Conclusion
4.结论
In this article, we learned about the HttpServletRequest object, which provides helpful methods to capture information about requesting clients. We also learned about the User-Agent header that provides clients with system-level information such as the browser family, OS family, etc.
在本文中,我们了解了 HttpServletRequest 对象,该对象提供了捕获请求客户端信息的有用方法。我们还了解了 User-Agent 标头,它可为客户端提供系统级信息,如浏览器系列、操作系统系列等。
Later, we also implemented the logic to capture client information from the request object.
随后,我们还实现了从请求对象中获取客户信息的逻辑。
As always, the example code is available over on GitHub.
在 GitHub 上提供了示例代码。