问题
I'm writing a Java RESTful service hosted on Heroku based on an example -> https://api.heroku.com/myapps/template-java-jaxrs/clone
My sample service is:
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();
}
}
My main is:
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")+"/";
}
}
My question is how can I find out in my service the IP address and port combination the request is coming from? I've read stuff on @Context which injects javax.ws.rs.core.HttpHeaders, javax.ws.rs.core.Request, etc. However, no incoming IP or port info is present.
I know if you implement com.sun.grizzly.tcp.Adapter, you can do something like:
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();
}
and access
request.remoteAddr()
But I'd really like to separate my RESTful API in a more structured way like in my first implementation.
Any help would be greatly appreciated. Thanks!
回答1:
As Luke said, when using Heroku, the remote host is the AWS application tier, therefore the EC2 ip address.
"X-Forwarded-For" header is the answer:
String ip = "0.0.0.0";
try {
ip = req.getHeader("X-Forwarded-For").split(",")[0];
} catch (Exception ignored){}
回答2:
You can inject 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();
}
回答3:
Based on @user647772 and @Ethan fusion. Thanks to them ;)
inject 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();
}
来源:https://stackoverflow.com/questions/13171265/how-to-find-out-incoming-restful-requests-ip-using-jax-rs-on-heroku