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

Posted

技术标签:

【中文标题】在 Servlet 中获取 HTTP 和 HTTPS 请求的完整 URL 和查询字符串【英文标题】:Get full URL and query string in Servlet for both HTTP and HTTPS requests 【发布时间】:2013-05-16 12:38:02 【问题描述】:

我正在编写一个代码,其任务是检索请求的 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() 的输出相同。

解决办法是什么?

【问题讨论】:

我认为很可能是您调用构造HttpServletRequest 的任何“其他函数”构造不正确。也许您可以创建一个 SSCCE 来演示确切的问题? 【参考方案1】:

我知道这是一个 Java 问题,但如果你使用 Kotlin,你可以很好地做到这一点:

val uri = request.run 
    if (queryString.isNullOrBlank()) requestURI else "$requestURI?$queryString"

【讨论】:

【参考方案2】:

当您尝试在服务器端构造 URL 时,HTTPS 请求变为 HTTP 的事实表明您可能有一个代理/负载平衡器(nginxpound 等)卸载 SSL 加密在前端并转发到您的后端服务,以简单的HTTP

如果是这样,请检查,

    您的代理是否已设置为正确转发标头(HostX-forwarded-protoX-forwarded-for 等)。 您的服务容器(例如Tomcat)是否设置为识别前面的代理。例如,Tomcat 需要将secure="true" scheme="https" proxyPort="443" 属性添加到其Connector 您的代码或服务容器是否正确处理标头。例如,当您将RemoteIpValve 添加到其Engine 时,Tomcat 会自动替换schemeremoteAddr 等值。 (请参阅Configuration guide、JavaDoc),因此您不必在代码中手动处理这些标头。

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

【讨论】:

这是问题的解决方案。扩展这个,read the server.xml Connector docs!【参考方案3】:

根据设计,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"
如果是https://domain 请求,.getScheme() 将给您"https".getServerName()http(s)://domain 上提供domain.getServerPort() 会给你端口。

使用下面的 sn-p:

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() : "");

上面的这个 sn-p 将获取完整的 URI,如果使用默认端口,则隐藏端口,如果未提供 "?" 和查询字符串,则不添加后者。

代理请求

请注意,如果您的请求通过代理,您需要查看 X-Forwarded-Proto 标头,因为该方案可能会被更改:

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

另外,一个常见的标头是X-Forwarded-For,它显示的是原始请求IP,而不是代理IP。

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

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

【讨论】:

您的第一个代码有助于在 https 中重复但出现错误。 https中没有查询字符串 已经更正了同样的错误。是的,我已经尝试过 getRequestURL() @ErBnAcharya getRequestURL() 必须工作。好像你做错了什么...... @ErBnAcharya 很奇怪你得到google.com:443 两次。另外我看到 http 而不是 https... 我对 @informatik01 的奇怪之处表示赞同。您可以执行以下操作:逐个打印,每行单独打印(getScheme() 在一个 getServerName() 在另一个),结果是什么?这将为您提供有关问题部分的提示。【参考方案4】:

简单使用:

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

【讨论】:

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

以上是关于在 Servlet 中获取 HTTP 和 HTTPS 请求的完整 URL 和查询字符串的主要内容,如果未能解决你的问题,请参考以下文章

获取此 org.springframework.web.servlet.DispatcherServlet noHandlerFound 错误和警告:在 Spring MVC 中未找到 HTTP 请求

servlet如何利用request来获取http请求中的主体信息?

servlet如何利用request来获取http请求中的主体信息?

Servlet ---[获取信息 , HTTP响应]

用jquery 如何获取servlet中输出的值

AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式