如何在Spring MVC Controller中提取IP地址?

joh*_*ohn 65 java spring-mvc ip-address

我正在开发Spring MVC控制器项目,我正在从浏览器中进行GET URL调用 -

以下是我通过浏览器进行GET调用的网址 -

http://127.0.0.1:8080/testweb/processing?workflow=test&conf=20140324&dc=all
Run Code Online (Sandbox Code Playgroud)

以下是在浏览器上点击后调用的代码 -

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc) {

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);

        // some other code
    }
Run Code Online (Sandbox Code Playgroud)

问题陈述:-

现在有什么办法,我可以从一些标题中提取IP地址吗?意思是我想知道哪个IP地址,呼叫即将到来,这意味着无论谁在上面调用URL,我都需要知道他们的IP地址.这可能吗?

Koi*_*oer 112

解决方案是

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc, HttpServletRequest request) {

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);
        System.out.println(request.getRemoteAddr());
        // some other code
    }
Run Code Online (Sandbox Code Playgroud)

添加HttpServletRequest request到方法定义,然后使用Servlet API

Spring文档在这里

15.3.2.3支持的处理程序方法参数和返回类型

Handler methods that are annotated with @RequestMapping can have very flexible signatures.
Most of them can be used in arbitrary order (see below for more details).

Request or response objects (Servlet API). Choose any specific request or response type,
for example ServletRequest or HttpServletRequest
Run Code Online (Sandbox Code Playgroud)

  • 感谢 Koitoer 的帮助。一个简单的问题,假设如果呼叫来自负载均衡器而不是特定机器,那么这也可以工作吗?我猜不会.. (2认同)
  • 如果来自邮递员的请求,我得到错误的 IP 地址 (0:0:0:0:0:0:0:1)。有谁知道,即使是邮递员的请求,如何获取IP地址? (2认同)

sun*_*kar 99

我来晚了,但这可能有助于寻找答案的人.通常servletRequest.getRemoteAddr()工作.

在许多情况下,您的应用程序用户可能通过代理服务器访问您的Web服务器,或者您的应用程序可能在负载均衡器后面.

因此,在这种情况下,您应该访问X-Forwarded-For http标头以获取用户的IP地址.

例如 String ipAddress = request.getHeader("X-FORWARDED-FOR");

希望这可以帮助.

  • 请注意,"X-Forwarded-For"通常是以逗号分隔的ips列表,链中的每个代理都将它看到的远程地址添加到列表中.因此,良好的实现通常会有一个受信任的代理列表,并在从右到左读取此标头时"跳过"这些ips. (9认同)
  • 请注意,例如 Tomcat 有“RemoteIpValve”,它解析“X-Forwarded-For”标头并将其设置在“HttpServletRequest”上,以便“servletRequest.getRemoteAddr()”返回正确的最终用户 IP 地址。在 Spring Boot 中,可以通过 `server.tomcat.remote-ip-header=X-Forwarded-For` 应用程序属性启用它 (2认同)

pan*_*ser 11

我用这种方法做到这一点

public class HttpReqRespUtils {

    private static final String[] IP_HEADER_CANDIDATES = {
        "X-Forwarded-For",
        "Proxy-Client-IP",
        "WL-Proxy-Client-IP",
        "HTTP_X_FORWARDED_FOR",
        "HTTP_X_FORWARDED",
        "HTTP_X_CLUSTER_CLIENT_IP",
        "HTTP_CLIENT_IP",
        "HTTP_FORWARDED_FOR",
        "HTTP_FORWARDED",
        "HTTP_VIA",
        "REMOTE_ADDR"
    };

    public static String getClientIpAddressIfServletRequestExist() {

        if (RequestContextHolder.getRequestAttributes() == null) {
            return "0.0.0.0";
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        for (String header: IP_HEADER_CANDIDATES) {
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) {
                String ip = ipList.split(",")[0];
                return ip;
            }
        }

        return request.getRemoteAddr();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我在哪里使用它? (2认同)

BaD*_*mer 8

就我而言,我在应用程序前面使用 Nginx,配置如下:

location / {
     proxy_pass        http://localhost:8080/;
     proxy_set_header  X-Real-IP $remote_addr;
     proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header  Host $http_host;
     add_header Content-Security-Policy 'upgrade-insecure-requests';
}
Run Code Online (Sandbox Code Playgroud)

所以在我的应用程序中我得到了真实的用户IP,如下所示:

String clientIP = request.getHeader("X-Real-IP");
Run Code Online (Sandbox Code Playgroud)


Rad*_*FID 7

您可以通过以下方式静态获取IP地址RequestContextHolder:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
        .getRequest();

String ip = request.getRemoteAddr();
Run Code Online (Sandbox Code Playgroud)


小智 7

见下文。此代码适用于 spring-boot 和 spring-boot + apache CXF/SOAP。

    // in your class RequestUtil
    private static final String[] IP_HEADER_NAMES = { 
                                                        "X-Forwarded-For",
                                                        "Proxy-Client-IP",
                                                        "WL-Proxy-Client-IP",
                                                        "HTTP_X_FORWARDED_FOR",
                                                        "HTTP_X_FORWARDED",
                                                        "HTTP_X_CLUSTER_CLIENT_IP",
                                                        "HTTP_CLIENT_IP",
                                                        "HTTP_FORWARDED_FOR",
                                                        "HTTP_FORWARDED",
                                                        "HTTP_VIA",
                                                        "REMOTE_ADDR"
                                                    };

    public static String getRemoteIP(RequestAttributes requestAttributes)
    {
        if (requestAttributes == null)
        {
            return "0.0.0.0";
        }
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String ip = Arrays.asList(IP_HEADER_NAMES)
            .stream()
            .map(request::getHeader)
            .filter(h -> h != null && h.length() != 0 && !"unknown".equalsIgnoreCase(h))
            .map(h -> h.split(",")[0])
            .reduce("", (h1, h2) -> h1 + ":" + h2);
        return ip + request.getRemoteAddr();
    }

    //... in service class:
    String remoteAddress = RequestUtil.getRemoteIP(RequestContextHolder.currentRequestAttributes());
Run Code Online (Sandbox Code Playgroud)

:)


Leo*_*eon 6

下面是Spring的方式,autowired在类中带有request bean @Controller

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Run Code Online (Sandbox Code Playgroud)

  • 这可能会导致跨多个线程并发使用控制器的问题。仅应使用“@Autowired”将单例注入到“@Controller”实例中。否则,您必须在控制器类上使用“@Scope(BeanDefinition.SCOPE_PROTOTYPE)”,以确保每个请求都会创建一个新的控制器实例。这效率较低,但如果您必须将某些内容作为属性注入到控制器类中,这是一种解决方法。 (5认同)

Bai*_*ong 6

将此方法放入您的 BaseController 中:

@SuppressWarnings("ConstantConditions")
protected String fetchClientIpAddr() {
    HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest();
    String ip = Optional.ofNullable(request.getHeader("X-FORWARDED-FOR")).orElse(request.getRemoteAddr());
    if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
    Assert.isTrue(ip.chars().filter($ -> $ == '.').count() == 3, "Illegal IP: " + ip);
    return ip;
}
Run Code Online (Sandbox Code Playgroud)