Java 如何从 http 或 https 请求获取带有端口的主机名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19598690/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:39:22  来源:igfitidea点击:

How to get host name with port from a http or https request

javahttpservletshttp-headershttprequest

提问by kumar

I have two applications deployed in jboss container(same unix box). If i get a request from app1, i need to frame a corresponding request for app2.

我在 jboss 容器(同一个 unix box)中部署了两个应用程序。如果我收到来自 app1 的请求,我需要为 app2 构建一个相应的请求。

eg:
if app1 request is: http://example.com/context?param1=123
then I need to extract "http://example.com/", so that I can frame request for second app.

例如:
如果 app1 请求是:http: //example.com/context?param1=123
那么我需要提取“ http://example.com/”,以便我可以为第二个应用程序构建请求。

I tried using:

我尝试使用:

  HttpServletRequest.getServerName() & 
  HttpServletRequest.getServerPort() & \
  HttpServletRequest.getHeader("host") 

methods, but the request may be of http or https.

方法,但请求可能是 http 或 https。

Please let me know if there is any other better way. Thanks!

请让我知道是否有其他更好的方法。谢谢!

采纳答案by David Levesque

You can use HttpServletRequest.getScheme()to retrieve either "http" or "https".

您可以使用HttpServletRequest.getScheme()检索“http”或“https”。

Using it along with HttpServletRequest.getServerName()should be enough to rebuild the portion of the URL you need.

与它一起使用HttpServletRequest.getServerName()应该足以重建您需要的 URL 部分。

You don't need to explicitly put the port in the URL if you're using the standard ones (80 for http and 443 for https).

如果您使用标准端口(http 为 80,https 为 443),则不需要明确地将端口放入 URL。

Edit: If your servlet container is behind a reverse proxy or load balancer that terminates the SSL, it's a bit trickier because the requests are forwarded to the servlet container as plain http. You have a few options:

编辑:如果您的 servlet 容器位于终止 SSL 的反向代理或负载平衡器之后,则有点棘手,因为请求将作为普通 http 转发到 servlet 容器。您有几个选择:

1) Use HttpServletRequest.getHeader("x-forwarded-proto")instead; this only works if your load balancer sets the header correctly (Apache should afaik).

1)HttpServletRequest.getHeader("x-forwarded-proto")改用;这仅在您的负载均衡器正确设置标头时才有效(Apache 应该是错误的)。

2) Configure a RemoteIpValvein JBoss/Tomcat that will make getScheme()work as expected. Again, this will only work if the load balancer sets the correct headers.

2)在 JBoss/Tomcat 中配置一个RemoteIpValve,它将getScheme()按预期工作。同样,这仅在负载均衡器设置正确的标头时才有效。

3) If the above don't work, you could configure two different connectors in Tomcat/JBoss, one for http and one for https, as described in this article.

3) 如果以上方法都不起作用,您可以在 Tomcat/JBoss 中配置两种不同的连接器,一种用于 http,一种用于 https,如本文所述

回答by jtahlborn

You can use HttpServletRequest.getRequestURLand HttpServletRequest.getRequestURI.

您可以使用HttpServletRequest.getRequestURLHttpServletRequest.getRequestURI

StringBuffer url = request.getRequestURL();
String uri = request.getRequestURI();
int idx = (((uri != null) && (uri.length() > 0)) ? url.indexOf(uri) : url.length());
String host = url.substring(0, idx); //base url
idx = host.indexOf("://");
if(idx > 0) {
  host = host.substring(idx); //remove scheme if present
}

回答by Christophe Roussy

If you want the original URL just use the method as described by jthalborn. If you want to rebuild the url do like David Levesque explained, here is a code snippet for it:

如果您想要原始 URL,只需使用 jthalborn 描述的方法。如果你想像 David Levesque 解释的那样重建 url,这里有一个代码片段:

final javax.servlet.http.HttpServletRequest req = (javax.servlet.http.HttpServletRequest) ...;
final int serverPort = req.getServerPort();
if ((serverPort == 80) || (serverPort == 443)) {
  // No need to add the server port for standard HTTP and HTTPS ports, the scheme will help determine it.
  url = String.format("%s://%s/...", req.getScheme(), req.getServerName(), ...);
} else {
  url = String.format("%s://%s:%s...", req.getScheme(), req.getServerName(), serverPort, ...);
}

You still need to consider the case of a reverse-proxy:

您仍然需要考虑反向代理的情况:

Could use constants for the ports but not sure if there is a reliable source for them, default ports:

可以为端口使用常量,但不确定是否有可靠的来源,默认端口:

Most developers will know about port 80 and 443 anyways, so constants are not that helpful.

无论如何,大多数开发人员都会知道端口 80 和 443,因此常量并没有那么有用。

Also see this similar post.

另请参阅此类似帖子

回答by W.Hao

If you use the load balancer & Nginx, config them without modify code.

如果您使用负载均衡器和 Nginx,请在不修改代码的情况下配置它们。

Nginx:

nginx:

proxy_set_header       Host $host;  
proxy_set_header  X-Real-IP  $remote_addr;  
proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;  
proxy_set_header X-Forwarded-Proto  $scheme;  

Tomcat's server.xml Engine:

Tomcat 的 server.xml 引擎:

<Valve className="org.apache.catalina.valves.RemoteIpValve"  
remoteIpHeader="X-Forwarded-For"  
protocolHeader="X-Forwarded-Proto"  
protocolHeaderHttpsValue="https"/> 

If only modify Nginx config file, the java code should be:

如果只修改Nginx配置文件,java代码应该是:

String XForwardedProto = request.getHeader("X-Forwarded-Proto");

回答by Mamun Sardar

If your server is running behind a proxy server, make sure your proxy header is set:

如果您的服务器在代理服务器后面运行,请确保设置了代理标头:

proxy_set_header X-Forwarded-Proto  $scheme;

Then to get the right scheme & urlyou can use springframework's classes:

然后为了得到正确的scheme & url你可以使用 springframework 的类:

public String getUrl(HttpServletRequest request) {
    HttpRequest httpRequest = new ServletServerHttpRequest(request);
    UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(httpRequest).build();

    String scheme = uriComponents.getScheme();             // http / https
    String serverName = request.getServerName();     // hostname.com
    int serverPort = request.getServerPort();        // 80
    String contextPath = request.getContextPath();   // /app

    // Reconstruct original requesting URL
    StringBuilder url = new StringBuilder();
    url.append(scheme).append("://");
    url.append(serverName);

    if (serverPort != 80 && serverPort != 443) {
        url.append(":").append(serverPort);
    }
    url.append(contextPath);
    return url.toString();
}

回答by CAM_344

I'm late to the party, but I had this same issue working with Java 8.

我迟到了,但我在使用 Java 8 时遇到了同样的问题。

This is what worked for me, on the HttpServletRequest requestobject.

这就是对我有用的HttpServletRequest request对象。

request.getHeader("origin");

and

request.getHeader("referer");

How I came to that conclusion:

我是如何得出这个结论的:

I have a java app running on http://localhost:3000making a Http Post to another java app I have running on http://localhost:8080.

我有一个在http://localhost:3000 上运行的 java 应用程序,向我在http://localhost:8080上运行的另一个 java 应用程序制作了一个 Http Post 。

From the Java code running on http://localhost:8080I couldn't get the http://localhost:3000from the HttpServletRequestusing the answers above. For me using the getHeadermethod with the correct string input worked.

从在http://localhost:8080上运行的 Java 代码中,我无法使用上述答案从HttpServletRequest 中获取http://localhost:3000。对我来说,使用具有正确字符串输入的方法有效。getHeader

request.getHeader("origin")gave me "http://localhost:3000"which is what I wanted.

request.getHeader("origin")给了我http://localhost:3000,这正是我想要的。

request.getHeader("referer")gave me "http://localhost:3000/xxxx"where xxxx is full URL I have from the requesting app.

request.getHeader("referer")给了我http://localhost:3000/xxxx,其中 xxxx 是我从请求应用程序获得的完整 URL。

回答by michal.jakubeczy

Seems like you need to strip the URL from the URL, so you can do it in a following way:

好像你需要从 URL 中剥离 URL,所以你可以通过以下方式进行:

request.getRequestURL().toString().replace(request.getRequestURI(), "")