在Servlet中获取HTTP和HTTPS请求的完整URL和查询字符串


77

我正在编写代码,该代码的任务是检索请求的URL或完整路径。我写了这段代码:

HttpServletRequest request;//obtained from other functions
String uri = request.getRequestURI();
if (request.getQueryString() != null)
    uri += "?" + request.getQueryString();

因此,当我浏览时http://google.com?q=abc,确定(正确)。但是浏览时出现问题https://google.com。的价值uri就是http://google.com:443google.com:443,所以程序不只做时HTTPS使用。

和的输出相同request.getRequestURL().toString()

解决办法是什么?


3
我认为很可能您调用构造的任何“其他函数”HttpServletRequest都错误地构造了它。也许您可以创建一个SSCCE来演示确切的问题?
parsifal

Answers:


167

通过设计,可以getRequestURL()为您提供完整的URL,仅缺少查询字符串。

在中HttpServletRequest,您可以使用以下方法获取URI的各个部分:

// Example: http://myhost:8080/people?lastname=Fox&age=30

String uri = request.getScheme() + "://" +   // "http" + "://
             request.getServerName() +       // "myhost"
             ":" +                           // ":"
             request.getServerPort() +       // "8080"
             request.getRequestURI() +       // "/people"
             "?" +                           // "?"
             request.getQueryString();       // "lastname=Fox&age=30"
  • .getScheme()"https"如果有https://domain要求,将会给您。
  • .getServerName()domainhttp(s)://domain
  • .getServerPort() 会给你港口。

使用以下代码段:

String uri = request.getScheme() + "://" +
             request.getServerName() + 
             ("http".equals(request.getScheme()) && request.getServerPort() == 80 || "https".equals(request.getScheme()) && request.getServerPort() == 443 ? "" : ":" + request.getServerPort() ) +
             request.getRequestURI() +
            (request.getQueryString() != null ? "?" + request.getQueryString() : "");

上面的代码片段将获取完整的URI,如果使用的是默认端口,则将隐藏端口;如果"?"未提供后者,则不添加和查询字符串。


代理要求

请注意,如果您的请求通过代理传递,则X-Forwarded-Proto由于格式可能会更改,因此您需要查看标头:

request.getHeader("X-Forwarded-Proto")

另外,通用标头是X-Forwarded-For,它显示原始请求IP而不是代理IP。

request.getHeader("X-Forwarded-For")

如果您自己负责代理/负载平衡器的配置,则需要确保在转发时设置了这些标头。


您的第一个代码有助于重复 https但出错。https
progrrammer

已更正,并且出现相同的错误。是的,我已经尝试过getRequestURL()
progrrammer

@ErBnAcharyagetRequestURL() 必须工作。好像您做错了什么...
informatik01

1
@ErBnAcharyagoogle.com:443 两次很奇怪。另外,我看到的是HTTP而不是https ...
informatik01

1
我第二次@ informatik01对此感到陌生。这里的东西,你可以这样做:一块一块印,每一个单独的行(getScheme()一个getServerName()在其他),有什么结果呢?这会给您有关问题部分的提示。
acdcjunior

9

只需使用:

String Uri = request.getRequestURL()+"?"+request.getQueryString();

请注意,这getRequestURL在错误页面上将不起作用。因此,如果您有404.jsp和需要重定向,则需要添加import:<%@ page import="org.apache.catalina.util.RequestUtil" %>并使用String requestedLocation = RequestUtil.filter((String) request.getAttribute("javax.servlet.error.request_uri"));
Nux,

3

一个事实HTTPS请求成为HTTP当你试图构建服务器端的URL表明你可能有一个代理/负载均衡器(nginxpound,等)卸载SSL加密前,期待在平原你的后端服务HTTP

如果是这样,请检查,

  1. 是否您的代理已经成立向前头正确(HostX-forwarded-protoX-forwarded-for等)。
  2. 是否Tomcat设置了服务容器(Eg )来识别前面的代理。例如,Tomcat需要secure="true" scheme="https" proxyPort="443"为其添加属性Connector
  3. 您的代码或服务容器是否正确处理了标头。例如,Tomcat自动替换schemeremoteAddr当你添加等价值RemoteIpValveEngine。(请参阅《配置指南JavaDoc),因此您不必在代码中手动处理这些标头。

request.getRequestURI()request.getRequestURL()尝试构造原始URL时,不正确的代理标头值可能会导致错误的输出。


这就是问题的解决方案。扩展此范围,请阅读server.xml连接器文档!
彼得-恢复莫妮卡

0

我知道这是一个Java问题,但是如果您使用的是Kotlin,则可以做得很好:

val uri = request.run {
    if (queryString.isNullOrBlank()) requestURI else "$requestURI?$queryString"
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.