Как извлечь IP-адрес в Spring MVC Controller get call?

93

Я работаю над проектом контроллера Spring MVC, в котором я выполняю вызов URL-адреса GET из браузера -

Ниже приведен URL-адрес, по которому я выполняю вызов GET из браузера -

http://127.0.0.1:8080/testweb/processing?workflow=test&conf=20140324&dc=all

А ниже приведен код, в котором вызов происходит после нажатия на браузер:

@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
    }

Постановка задачи:-

Есть ли способ извлечь IP-адрес из заголовка? Это означает, что я хотел бы знать, с какого IP-адреса идет звонок. То есть, кто бы ни звонил по указанному выше URL-адресу, мне нужно знать его IP-адрес. Возможно ли это сделать?

Джон
источник
Попробуйте использовать Spring AOP и обработать HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Ответы:

148

Решение

@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
    }

Добавьте HttpServletRequest requestв определение вашего метода, а затем используйте 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
Koitoer
источник
1
Спасибо Koitoer за помощь. Один быстрый вопрос: предположим, если вызов поступает от Load Balancer, а не от конкретной машины, то это тоже сработает? Думаю, нет ..
Джон
Нет, это не так, но в
балансировщике нагрузки
Убедитесь, что балансировщик нагрузки может отправлять эти значения в заголовке, поэтому рассмотрите возможность использования метода getHeader для HttpServletRequest.
Koitoer 05
Koitoer Работает отлично !! Но есть другой способ, кроме HttpServletRequest.
Харшал Патил
1
Это устарело.
Gewure
112

Я здесь опаздываю, но это может помочь кому-то найти ответ. Обычно servletRequest.getRemoteAddr()работает.

Во многих случаях пользователи вашего приложения могут обращаться к вашему веб-серверу через прокси-сервер или ваше приложение находится за балансировщиком нагрузки.

Таким образом, в таком случае вы должны получить доступ к HTTP-заголовку X-Forwarded-For, чтобы получить IP-адрес пользователя.

например String ipAddress = request.getHeader("X-FORWARDED-FOR");

Надеюсь это поможет.

суниткаткар
источник
11
Обратите внимание, что X-Forwarded-Forобычно это список IP-адресов, разделенных запятыми, где каждый прокси в цепочке добавляет в список удаленный адрес, который он видит. Таким образом, хорошая реализация обычно имеет список доверенных прокси и пропускает эти IP-адреса при чтении этого заголовка справа налево.
Раман
как получить IP-адрес как 111.111.111.111/X
Муниб Мирза
26

Я использую такой метод для этого

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();
    }
}
пансер
источник
1
где мне его использовать?
Maifee Ul Asad
12

Вы можете получить статический IP-адрес, как показано RequestContextHolderниже:

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

String ip = request.getRemoteAddr();
Радуан РУФИД
источник
4

Поместите этот метод в свой 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;
}
BaiJiFeiLong
источник
4

Увидеть ниже. Этот код работает с 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());

:)

Вагнер Ногейра
источник
3

Ниже приведен способ Spring с autowiredкомпонентом запроса в @Controllerклассе:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());
Леон
источник
1
Это могло вызвать проблемы с одновременным использованием контроллера в нескольких потоках. Только синглтоны следует вводить в @Controllerэкземпляры с использованием @Autowired. В противном случае вы должны использовать @Scope(BeanDefinition.SCOPE_PROTOTYPE)класс контроллера, чтобы гарантировать создание нового экземпляра контроллера с каждым запросом. Это менее эффективно, но это обходной путь, если вам нужно добавить что-то в качестве свойства в класс контроллера.
Энди
1

В моем случае я использовал 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';
}

поэтому в моем приложении я получаю реальный IP-адрес пользователя, например:

String clientIP = request.getHeader("X-Real-IP");
БаДр Амер
источник
0
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 getIPFromRequest(HttpServletRequest request) {
        String ip = null;
        if (request == null) {
            if (RequestContextHolder.getRequestAttributes() == null) {
                return null;
            }
            request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }

        try {
            ip = InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (!StringUtils.isEmpty(ip))
            return ip;

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

        return request.getRemoteAddr();
    }

Я комбинирую приведенный выше код с этим кодом, работающим в большинстве случаев. Передайте полученное HttpServletRequest requestот api методу

Kyo Huu
источник