Làm thế nào để trích xuất địa chỉ IP trong Spring MVC Controller nhận cuộc gọi?


93

Tôi đang làm việc trên dự án bộ điều khiển Spring MVC, trong đó tôi đang thực hiện lệnh gọi GET URL từ trình duyệt -

Dưới đây là url mà tôi đang thực hiện cuộc gọi GET từ trình duyệt -

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

Và dưới đây là mã mà cuộc gọi đến sau khi nhấn vào trình duyệt -

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

Báo cáo vấn đề:-

Bây giờ có cách nào, tôi có thể trích xuất Địa chỉ IP từ một số tiêu đề? Có nghĩa là tôi muốn biết từ Địa chỉ IP nào, cuộc gọi đến, nghĩa là bất kỳ ai đang gọi ở trên URL, tôi cần biết Địa chỉ IP của họ. Đây có phải là có thể làm gì?


Hãy thử sử dụng Spring AOP và xử lý HttpServletRequest. stackoverflow.com/questions/19271807/…
Dilip G

Câu trả lời:


149

Giải pháp là

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

Thêm vào HttpServletRequest requestđịnh nghĩa phương thức của bạn và sau đó sử dụng API Servlet

Tài liệu Mùa xuân ở đây cho biết trong

15.3.2.3 Các đối số phương thức xử lý được hỗ trợ và kiểu trả về

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
Cảm ơn Koitoer vì sự giúp đỡ. Một câu hỏi nhanh, giả sử nếu cuộc gọi đến từ Load Balancer thay vì máy cụ thể thì điều này cũng sẽ hoạt động? Tôi đoán là không ..
john

Không It wont, nhưng có một số cấu hình trong loadbalancer có thể gửi các IP như họ không tồn tại, có lẽ đây là trường hợp của bạn
Koitoer

Kiểm tra xem bộ cân bằng tải có thể gửi những giá trị đó trong tiêu đề, vì vậy hãy xem xét sử dụng phương thức getHeader của HttpServletRequest.
Koitoer

Koitoer Nó hoạt động hoàn hảo !! Nhưng có bất kỳ cách nào khác thay vì HttpServletRequest.
Harshal Patil

1
Điều này không được dùng nữa.
Gewure

112

Tôi đến muộn ở đây, nhưng điều này có thể giúp ai đó đang tìm kiếm câu trả lời. Các servletRequest.getRemoteAddr()công trình điển hình .

Trong nhiều trường hợp, người dùng ứng dụng của bạn có thể đang truy cập máy chủ web của bạn thông qua máy chủ proxy hoặc có thể ứng dụng của bạn đang ở sau trình cân bằng tải.

Vì vậy, bạn nên truy cập tiêu đề X-Forwarded-For http trong trường hợp như vậy để lấy địa chỉ IP của người dùng.

ví dụ String ipAddress = request.getHeader("X-FORWARDED-FOR");

Hi vọng điêu nay co ich.


11
Lưu ý rằng X-Forwarded-Forthường là danh sách các ips được phân tách bằng dấu phẩy, với mỗi proxy trong chuỗi sẽ thêm địa chỉ từ xa mà nó thấy vào danh sách. Vì vậy, một triển khai tốt thường sẽ có một danh sách các proxy đáng tin cậy và "bỏ qua" các ips đó khi đọc tiêu đề này từ phải sang trái.
Raman

làm thế nào để có được địa chỉ ip như 111.111.111.111/X
Muneeb Mirza

26

Tôi sử dụng phương pháp như vậy để làm điều này

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
tôi sử dụng nó ở đâu?
Maifee Ul Asad

12

Bạn có thể lấy địa chỉ IP tĩnh từ RequestContextHoldernhư sau:

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

String ip = request.getRemoteAddr();

4

Đặt phương thức này trong BaseController của bạn:

@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

Xem bên dưới. Mã này hoạt động với spring-boot và 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

Dưới đây là Spring way, với autowiredrequest bean trong @Controllerlớp:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());

1
Điều này có thể gây ra sự cố với việc sử dụng đồng thời bộ điều khiển trên nhiều luồng. Chỉ các singleton nên được tiêm vào các @Controllertrường hợp sử dụng @Autowired. Nếu không, bạn phải sử dụng @Scope(BeanDefinition.SCOPE_PROTOTYPE)trên lớp bộ điều khiển để đảm bảo rằng một phiên bản mới của bộ điều khiển được thực hiện với mọi yêu cầu. Điều này kém hiệu quả hơn, nhưng là một giải pháp thay thế nếu bạn phải đưa thứ gì đó làm thuộc tính vào lớp bộ điều khiển.
Andy

1

Trong trường hợp của tôi, tôi đang sử dụng Nginx trước ứng dụng của mình với cấu hình sau:

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

vì vậy trong ứng dụng của tôi, tôi nhận được ip người dùng thực như vậy:

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

Tôi lược bỏ mã ở trên để mã này hoạt động cho hầu hết các trường hợp. Chuyển những HttpServletRequest requestgì bạn nhận được từ api đến phương thức

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.