SpringBoot獲取瀏覽器信息的多種實(shí)現(xiàn)方式
引言
在Web開發(fā)中,獲取用戶瀏覽器信息是常見需求,可用于統(tǒng)計(jì)分析、個(gè)性化展示、安全防護(hù)等場景。SpringBoot提供了多種方式來獲取這些信息,下面是詳細(xì)實(shí)現(xiàn)方法。
一、獲取基本請求信息
1. 獲取客戶端IP地址
在SpringBoot中,最基本的方法是通過HttpServletRequest對象獲取IP地址,但需要注意反向代理的情況。
public class IpUtils {
private static final String UNKNOWN = "unknown";
/**
* 獲取真實(shí)IP地址(考慮反向代理情況)
*/
public static String getIpAddr(HttpServletRequest request) {
if (request == null) {
return UNKNOWN;
}
// 嘗試從各種代理頭中獲取IP
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
// 如果還是沒有獲取到,使用RemoteAddr
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 處理多級代理的情況,取第一個(gè)IP
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
// 本地測試情況
if ("0:0:0:0:0:0:0:1".equals(ip)) {
ip = "127.0.0.1";
}
return ip;
}
}
2. 獲取請求頭信息
@RestController
public class BrowserInfoController {
@GetMapping("/browser-info")
public Map<String, String> getBrowserInfo(HttpServletRequest request) {
Map<String, String> info = new HashMap<>();
// 獲取IP地址
info.put("ip", IpUtils.getIpAddr(request));
// 獲取User-Agent
info.put("userAgent", request.getHeader("User-Agent"));
// 獲取其他請求頭信息
info.put("accept", request.getHeader("Accept"));
info.put("acceptLanguage", request.getHeader("Accept-Language"));
info.put("referer", request.getHeader("Referer"));
info.put("contentType", request.getHeader("Content-Type"));
info.put("encoding", request.getHeader("Accept-Encoding"));
info.put("connection", request.getHeader("Connection"));
return info;
}
}
二、使用UserAgentUtils解析瀏覽器信息
1. 添加依賴
<!-- pom.xml -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
2. 解析瀏覽器詳細(xì)信息
public class BrowserUtils {
/**
* 解析瀏覽器信息
*/
public static Map<String, Object> parseBrowserInfo(String userAgentString) {
Map<String, Object> result = new HashMap<>();
// 創(chuàng)建UserAgent對象
UserAgent userAgent = UserAgent.parseUserAgentString(userAgentString);
// 獲取瀏覽器信息
Browser browser = userAgent.getBrowser();
Version browserVersion = userAgent.getBrowserVersion();
result.put("browser", browser.getName());
result.put("browserVersion", browserVersion.getVersion());
// 獲取操作系統(tǒng)信息
OperatingSystem os = userAgent.getOperatingSystem();
result.put("operatingSystem", os.getName());
// 獲取設(shè)備信息
DeviceType deviceType = os.getDeviceType();
result.put("deviceType", deviceType.getName());
// 判斷是否是移動設(shè)備
result.put("isMobile", os.isMobileDevice());
// 獲取渲染引擎
RenderingEngine engine = userAgent.getRenderingEngine();
result.put("renderingEngine", engine.name());
return result;
}
}
3. 在Controller中使用
@RestController
public class BrowserInfoController {
@GetMapping("/detailed-browser-info")
public Map<String, Object> getDetailedBrowserInfo(HttpServletRequest request) {
Map<String, Object> info = new HashMap<>();
// 獲取IP
String ip = IpUtils.getIpAddr(request);
info.put("ip", ip);
// 獲取并解析User-Agent
String userAgentString = request.getHeader("User-Agent");
Map<String, Object> browserDetails = BrowserUtils.parseBrowserInfo(userAgentString);
info.putAll(browserDetails);
return info;
}
}
三、獲取IP地址歸屬地
1. 使用ip2region庫(本地解析)
添加依賴:
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>2.6.3</version>
</dependency>
實(shí)現(xiàn)代碼:
public class IpRegionUtils {
private static Searcher searcher;
// 初始化ip2region
static {
try {
// 下載xdb文件到resources目錄
String dbPath = IpRegionUtils.class.getResource("/ip2region.xdb").getPath();
// 創(chuàng)建searcher對象
searcher = Searcher.newWithFileOnly(dbPath);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取IP地址歸屬地
*/
public static String getCityInfo(String ip) {
if (searcher == null || ip == null) {
return "未知";
}
try {
long startTime = System.nanoTime();
String region = searcher.search(ip);
long endTime = System.nanoTime();
System.out.printf("IP: %s, 歸屬地: %s, 耗時(shí): %f 微秒\n",
ip, region, (endTime - startTime) / 1000000.0);
return region;
} catch (Exception e) {
e.printStackTrace();
}
return "未知";
}
// 程序結(jié)束時(shí)釋放資源
public static void close() {
if (searcher != null) {
try {
searcher.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2. 使用第三方API(在線解析)
public class IpLocationUtils {
private static final String IP_API_URL = "https://api.ip2location.com/v2/?key=YOUR_API_KEY&ip=%s&package=WS3"
/**
* 通過第三方API獲取IP歸屬地
*/
public static String getIpLocation(String ip) {
try {
String url = String.format(IP_API_URL, ip);
String result = HttpUtil.get(url);
// 解析JSON結(jié)果
JSONObject jsonObject = JSON.parseObject(result);
String country = jsonObject.getString("country_name");
String region = jsonObject.getString("region_name");
String city = jsonObject.getString("city_name");
return country + " " + region + " " + city;
} catch (Exception e) {
e.printStackTrace();
return "未知";
}
}
}
四、創(chuàng)建統(tǒng)一的瀏覽器信息工具類
@Component
public class ClientInfoUtil {
/**
* 獲取完整的客戶端信息
*/
public Map<String, Object> getClientInfo() {
HttpServletRequest request = getCurrentRequest();
if (request == null) {
return Collections.emptyMap();
}
Map<String, Object> clientInfo = new HashMap<>();
// 獲取IP地址
String ip = IpUtils.getIpAddr(request);
clientInfo.put("ip", ip);
// 獲取IP歸屬地
clientInfo.put("location", IpRegionUtils.getCityInfo(ip));
// 獲取并解析User-Agent
String userAgentString = request.getHeader("User-Agent");
Map<String, Object> browserInfo = BrowserUtils.parseBrowserInfo(userAgentString);
clientInfo.putAll(browserInfo);
// 獲取其他有用信息
clientInfo.put("sessionId", request.getSession().getId());
clientInfo.put("requestUrl", request.getRequestURL().toString());
clientInfo.put("referer", request.getHeader("Referer"));
clientInfo.put("timestamp", System.currentTimeMillis());
return clientInfo;
}
/**
* 獲取當(dāng)前請求
*/
private HttpServletRequest getCurrentRequest() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
if (attributes instanceof ServletRequestAttributes) {
return ((ServletRequestAttributes) attributes).getRequest();
}
return null;
}
}
五、實(shí)際應(yīng)用場景
1. 訪問日志記錄
@Aspect
@Component
@Slf4j
public class AccessLogAspect {
@Autowired
private ClientInfoUtil clientInfoUtil;
@Pointcut("execution(* com.example.controller.*.*(..))")
public void logPointCut() {}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long startTime = System.currentTimeMillis();
// 獲取客戶端信息
Map<String, Object> clientInfo = clientInfoUtil.getClientInfo();
// 執(zhí)行目標(biāo)方法
Object result = point.proceed();
// 記錄訪問日志
long endTime = System.currentTimeMillis();
log.info("訪問日志: {}", JSON.toJSONString(clientInfo));
log.info("處理時(shí)間: {}ms", endTime - startTime);
return result;
}
}
2. 安全驗(yàn)證中間件
@Component
public class SecurityCheckFilter extends OncePerRequestFilter {
@Autowired
private ClientInfoUtil clientInfoUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// 獲取客戶端信息
Map<String, Object> clientInfo = clientInfoUtil.getClientInfo();
// 進(jìn)行安全檢查(示例:檢查是否是異常瀏覽器)
String browser = (String) clientInfo.get("browser");
if ("不支持的瀏覽器".equals(browser)) {
response.setStatus(403);
response.getWriter().write("不支持的瀏覽器,請使用主流瀏覽器訪問");
return;
}
// 繼續(xù)過濾鏈
filterChain.doFilter(request, response);
}
}
六、注意事項(xiàng)
- 反向代理處理:在使用Nginx等反向代理時(shí),需要正確配置代理頭,確保能獲取到真實(shí)IP
- 性能考慮:IP歸屬地查詢可能影響性能,建議使用緩存
- 隱私保護(hù):獲取用戶信息時(shí)要遵守相關(guān)隱私法規(guī)
- 依賴更新:UserAgentUtils庫已停止維護(hù),可考慮使用其他替代方案如yauaa
- 錯(cuò)誤處理:網(wǎng)絡(luò)請求和解析過程中要做好異常處理
通過以上方法,你可以在SpringBoot項(xiàng)目中全面獲取和處理瀏覽器相關(guān)信息,為應(yīng)用提供更豐富的功能和更好的用戶體驗(yàn)。
到此這篇關(guān)于SpringBoot獲取瀏覽器信息的多種實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)SpringBoot獲取瀏覽器信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏
在當(dāng)今數(shù)據(jù)安全越來越受到重視的背景下,許多企業(yè)都對敏感數(shù)據(jù)的保護(hù)有著嚴(yán)格的要求,本文就來深入探討一下如何自定義注解來實(shí)現(xiàn)對敏感數(shù)據(jù)的脫敏處理吧2024-11-11
JAVA Spring中讓人頭痛的JAVA大事務(wù)問題要如何解決你知道嗎
這篇文章主要介紹了Java Spring事務(wù)使用及驗(yàn)證過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-09-09
springboot項(xiàng)目同時(shí)啟動web服務(wù)和grpc服務(wù)的方法
本文主要介紹了springboot項(xiàng)目同時(shí)啟動web服務(wù)和grpc服務(wù)的方法,通過實(shí)際代碼示例展示了實(shí)現(xiàn),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02
SpringBoot用多線程批量導(dǎo)入數(shù)據(jù)庫實(shí)現(xiàn)方法
這篇文章主要介紹了SpringBoot用多線程批量導(dǎo)入數(shù)據(jù)庫實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-02-02
關(guān)于Java for循環(huán)的正確用法介紹
Java里的循環(huán)結(jié)構(gòu)我們可以通過while、do-while、for、foreach等方式實(shí)現(xiàn)循環(huán),這篇文章會把這幾種循環(huán)方式都給大家講解到,但本文主要介紹for循環(huán)的使用,感興趣的同學(xué)可以參考閱讀2023-05-05
eclipse創(chuàng)建springboot項(xiàng)目的三種方式總結(jié)
這篇文章主要介紹了eclipse創(chuàng)建springboot項(xiàng)目的三種方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring Boot集成Spring Cloud Security進(jìn)行安全增強(qiáng)的方法
Spring Cloud Security是Spring Security的擴(kuò)展,它提供了對Spring Cloud體系中的服務(wù)認(rèn)證和授權(quán)的支持,包括OAuth2、JWT等,這篇文章主要介紹了Spring Boot集成Spring Cloud Security進(jìn)行安全增強(qiáng),需要的朋友可以參考下2024-11-11

