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