Як отримати IP-адресу у весняному контролері MVC, коли дзвонять?


93

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

Нижче вказана 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/…
Діліп Г

Відповіді:


149

Рішення є

@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 сервлетів

Весняна документація, сказана тут

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

1
Дякуємо Koitoer за допомогу. Одне швидке запитання, припустимо, якщо дзвінок надходить від Load Balancer замість певної машини, тоді це буде працювати також? Я думаю, ні ..
Джон

Ні, це не так, але в loadbalancer є деякі конфігурації, які можуть надсилати IP, оскільки вони не існують, ймовірно, це ваш випадок
Koitoer

Перевірте, ймовірно, балансир навантаження може надсилати ці значення в заголовок, тому подумайте про використання методу getHeader HttpServletRequest.
Koitoer

Koitoer Це чудово працює !! Але існує будь-який інший спосіб, а не HttpServletRequest.
Harshal Patil

1
Це застаріло.
Gewure

112

Я запізнююсь тут, але це може допомогти тому, хто шукає відповідь. Зазвичай servletRequest.getRemoteAddr()працює.

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

Отже, вам слід отримати доступ до заголовка X-Forwarded-For http у такому випадку, щоб отримати IP-адресу користувача.

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

Сподіваюся, це допомагає.


11
Зверніть увагу, що X-Forwarded-Forце, як правило, розділений комами список ips, при цьому кожен проксі-сервер в ланцюжку додає віддалену адресу, яку він бачить, до списку. Отже, хороша реалізація, як правило, має список довірених проксі-серверів і "пропускає" ці ips під час читання цього заголовка справа наліво.
Раман

як отримати ip-адресу як 111.111.111.111/X
Muneeb Mirza

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

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

Нижче весняний спосіб із autowiredзапитом bean у @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 метод

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.