【问题标题】:How to find out incoming RESTful request's IP using JAX-RS on Heroku?如何在 Heroku 上使用 JAX-RS 找出传入的 RESTful 请求的 IP?
【发布时间】:2012-10-21 16:44:19
【问题描述】:

我正在编写基于示例托管在 Heroku 上的 Java RESTful 服务 -> https://api.heroku.com/myapps/template-java-jaxrs/clone

我的示例服务是:

package com.example.services;

import com.example.models.Time;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/time")
@Produces(MediaType.APPLICATION_JSON)
public class TimeService {

    @GET
    public Time get() {
        return new Time();
    }

}

我的主要是:

public class Main {

    public static final String BASE_URI = getBaseURI();

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{
        final Map<String, String> initParams = new HashMap<String, String>();
        initParams.put("com.sun.jersey.config.property.packages","services.contracts"); 

        System.out.println("Starting grizzly...");
        SelectorThread threadSelector = GrizzlyWebContainerFactory.create(BASE_URI, initParams);
        System.out.println(String.format("Jersey started with WADL available at %sapplication.wadl.",BASE_URI, BASE_URI));
    }

    private static String getBaseURI() 
    {
        return "http://localhost:"+(System.getenv("PORT")!=null?System.getenv("PORT"):"9998")+"/";      
    }

}

我的问题是如何在我的服务中找到请求来自的 IP 地址和端口组合?我在@Context 上阅读了注入 javax.ws.rs.core.HttpHeaders、javax.ws.rs.core.Request 等的内容。但是,没有传入的 IP 或端口信息。

我知道如果你实现了 com.sun.grizzly.tcp.Adapter,你可以这样做:

public static void main(String[] args) {
    SelectorThread st = new SelectorThread();
    st.setPort(8282);
    st.setAdapter(new EmbeddedServer());
    try {
        st.initEndpoint();
        st.startEndpoint();
    } catch (Exception e) {
        System.out.println("Exception in SelectorThread: " + e);
    } finally {
        if (st.isRunning()) {
            st.stopEndpoint();
        }
    }
}

public void service(Request request, Response response)
        throws Exception {
    String requestURI = request.requestURI().toString();

    System.out.println("New incoming request with URI: " + requestURI);
    System.out.println("Request Method is: " + request.method());

    if (request.method().toString().equalsIgnoreCase("GET")) {
        response.setStatus(HttpURLConnection.HTTP_OK);
        byte[] bytes = "Here is my response text".getBytes();

        ByteChunk chunk = new ByteChunk();
        response.setContentLength(bytes.length);
        response.setContentType("text/plain");
        chunk.append(bytes, 0, bytes.length);
        OutputBuffer buffer = response.getOutputBuffer();
        buffer.doWrite(chunk, response);
        response.finish();
    }
}

public void afterService(Request request, Response response)
        throws Exception {
    request.recycle();
    response.recycle();
}

并访问

    request.remoteAddr()

但我真的很想以更结构化的方式分离我的 RESTful API,就像我的第一个实现一样。

任何帮助将不胜感激。谢谢!

【问题讨论】:

    标签: rest heroku jersey jax-rs grizzly


    【解决方案1】:

    你可以注入HttpServletRequest:

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Response getIp(@Context HttpServletRequest req) {
        String remoteHost = req.getRemoteHost();
        String remoteAddr = req.getRemoteAddr();
        int remotePort = req.getRemotePort();
        String msg = remoteHost + " (" + remoteAddr + ":" + remotePort + ")";
        return Response.ok(msg).build();
    }
    

    【讨论】:

    • 感谢您的信息,但是当我运行它时,我得到的 IP 与发出请求的客户端的公共 IP 不同。我在 Heroku 上运行该服务,恐怕它可能是某个 Heroku 中介的 IP(进行路由/负载平衡的 IP)。我将如何解决这个问题?
    • 我查了一下主机名,req.getRemoteHost()确实是私有IPip-10-42-223-182.ec2.internal,好像是EC2的IP。
    • 我想通了,你必须从 Http Header 中提取 X-Forwarded-For 标头。
    • 只是想向任何来到这里使用 JAX-RS 进行 maven 配置的人提及原始海报问题中所述的问题。你必须在你的pom.xmlmvnrepository.com/artifact/javax.servlet/servlet-api/2.5)中包括javax-servlet for servlet-api,然后是import javax.servlet.http.HttpServletRequestContext 类已经在 J​​AX-RS 中:import javax.ws.rs.core.Context
    • 嗨@Sonny 感谢您的评论。你知道有什么方法可以通过 JAX RS 方式获取远程 IP(没有 servlet-api)吗?
    【解决方案2】:

    正如 Luke 所说,在使用 Heroku 时,远程主机是 AWS 应用层,因此是 EC2 ip 地址。

    “X-Forwarded-For”标题就是答案:

    String ip = "0.0.0.0";
    try {
        ip = req.getHeader("X-Forwarded-For").split(",")[0];
    } catch (Exception ignored){}
    

    【讨论】:

      【解决方案3】:

      基于@user647772 和@Ethan 融合。感谢他们 ;)

      注入HttpServletRequest:

      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response getFromp(@Context HttpServletRequest req) {
          String from = _getUserFrom(req);
          return Response.ok(from).build();
      }
      
      private String _getUserFrom(HttpServletRequest req) {
          String xForwardedFor = req.getHeader("X-Forwarded-For");
          xForwardedFor = xForwardedFor != null && xForwardedFor.contains(",") ? xForwardedFor.split(",")[0]:xForwardedFor;
          String remoteHost = req.getRemoteHost();
          String remoteAddr = req.getRemoteAddr();
          int remotePort = req.getRemotePort();
          StringBuffer sb = new StringBuffer();
          if (remoteHost != null 
          && !"".equals(remoteHost)
          && !remoteHost.equals(remoteAddr)) {
              sb.append(remoteHost).append(" ");
          }
          if (xForwardedFor != null 
          && !"".equals(xForwardedFor)) {
              sb.append(xForwardedFor).append("(fwd)=>");
          }
          if (remoteAddr != null || !"".equals(remoteAddr)) {
              sb.append(remoteAddr).append(":").append(remotePort);
          }
          return sb.toString();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-13
        • 2013-07-13
        • 1970-01-01
        • 2023-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多