如何在Spring Boot控制器中获取客户端主机/域名信息
解决Spring Boot API获取调用方主机名及端口的问题
问题分析
你遇到的是后端服务间调用的标识问题:
Origin和Referer是浏览器专属请求头,RestTemplate这类后端HTTP客户端不会自动携带,所以API端获取不到是正常现象。getRemoteAddr()返回的是客户端请求的IP(本地调用时通常是127.0.0.1),但默认拿不到调用方应用的固定端口(比如9000),因为RestTemplate发起请求时用的是临时随机端口,而非应用的服务端口。
可行解决方案
方案1:调用方主动携带自定义标识头(最可靠)
让每个调用API的Java应用在请求头中添加自定义的客户端信息,包含主机名和应用端口,API端直接读取该头即可。
调用方(RestTemplate)修改代码:
RestTemplate restTemplate1 = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // 添加自定义客户端标识头 // 若为Spring Boot应用,可注入ServerProperties动态获取自身服务端口 String clientHost = InetAddress.getLocalHost().getHostName() + ":9000"; headers.add("X-Client-Identity", clientHost); Map<String, String> map = new HashMap<>(); map.put("username", "test"); map.put("password", "test"); String jsonBody = new ObjectMapper().writeValueAsString(map); HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers); ResponseEntity<String> response = restTemplate1.exchange( "http://localhost:8000/test", HttpMethod.POST, entity, String.class );
API端(控制器)读取标识:
@PostMapping("/test") public String authenticateAndGetToken(HttpServletRequest httpServletRequest, @RequestBody Request request) { // 读取自定义客户端标识 String clientIdentity = httpServletRequest.getHeader("X-Client-Identity"); Log.info("调用方信息:" + clientIdentity); // 原有业务逻辑 String errorMsg = "Invalid UserName"; UserDetails userDetails = userInfoService.loadUserByUsername(request.getUsername()); // ... 后续代码 }
方案2:通过远程IP+端口反查主机名(仅能获取请求临时端口)
如果不需要调用方的应用固定端口,仅需识别请求来源的主机和临时请求端口,可通过HttpServletRequest的远程信息结合IP反查实现:
@PostMapping("/test") public String authenticateAndGetToken(HttpServletRequest httpServletRequest, @RequestBody Request request) { String clientIp = httpServletRequest.getRemoteAddr(); int clientPort = httpServletRequest.getRemotePort(); // 通过IP反查主机名 String clientHostname = ""; try { InetAddress addr = InetAddress.getByName(clientIp); clientHostname = addr.getHostName(); } catch (UnknownHostException e) { clientHostname = clientIp; // 反查失败时用IP替代 } String clientInfo = clientHostname + ":" + clientPort; Log.info("调用方请求信息:" + clientInfo); // 原有业务逻辑 // ... }
注意:此方案拿到的端口是RestTemplate发起请求时使用的临时端口,并非调用方应用的服务端口(9000),仅适用于识别请求来源主机,无法定位到具体应用。
内容的提问来源于stack exchange,提问作者Pavan G
相关产品推荐
相关产品推荐

