HttpServletRequest如何转换为完整的URL

294

我有一个 HttpServletRequest 对象。

如何获取完整和精确的 URL,以导致此调用到达我的 Servlet?

或者至少尽可能准确地获取,因为有些东西可以重新生成(例如参数的顺序)。


另请参阅:https://dev59.com/aW445IYBdhLWcg3wTIjm - Christophe Roussy
为什么我们没有一个实用函数来处理它? - vanduc1102
12个回答

463

HttpServletRequest有以下方法:

因此,要获取完整URL,只需执行:

public static String getFullURL(HttpServletRequest request) {
    StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString());
    String queryString = request.getQueryString();

    if (queryString == null) {
        return requestURL.toString();
    } else {
        return requestURL.append('?').append(queryString).toString();
    }
}

3
你复制了getRequestURI的描述(错误),但在代码中使用了getRequestURL(正确)。 - Vinko Vrsalovic
22
你需要有条件地检查查询字符串是否为空。 - Adam Gent
8
您还改变了支持请求URL的StringBuffer。如果请求实现没有进行防御性复制,这将是引入奇怪行为和错误的非常好的方式,同时也会影响到其他代码对其原始形式的依赖。 - Ken Blair
5
请使用StringBuilder而不是StringBuffer。 - Gladwin Burboz
20
@KenBlair说:StringBuffer被有意地返回,这样你就可以轻松地添加更多的内容。由于这在javadoc中已经说明,因此实现方希望调用者能够修改返回的StringBuffer,否则这将非常荒谬。因此,这很好。 - stolsvik
显示剩余14条评论

169

我使用这种方法:

public static String getURL(HttpServletRequest req) {

    String scheme = req.getScheme();             // http
    String serverName = req.getServerName();     // hostname.com
    int serverPort = req.getServerPort();        // 80
    String contextPath = req.getContextPath();   // /mywebapp
    String servletPath = req.getServletPath();   // /servlet/MyServlet
    String pathInfo = req.getPathInfo();         // /a/b;c=123
    String queryString = req.getQueryString();          // d=789

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

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

    url.append(contextPath).append(servletPath);

    if (pathInfo != null) {
        url.append(pathInfo);
    }
    if (queryString != null) {
        url.append("?").append(queryString);
    }
    return url.toString();
}

9
这是一个有关HttpServletRequest所有信息的快速参考的有用答案。然而,在决定是否要将端口添加到结果中时,我认为您需要检查方案。例如,“https”是443。 - Peter Cardona
2
一个小优化是使用StringBuilder而不是StringBuffer,只是一个提示。 - Chris
这取决于您是否需要同步。我认为小心谨慎总比后悔好。因此,如果有人需要代码更快,他们应该使用 StringBuilder,但如果您想要线程安全,请坚持本答案中的内容。 - MatBanik
11
仅做评论:在这个特定的例子中,线程安全不是一个问题,因为url仅在该方法内声明、实例化和使用,所以它不能从调用该方法的线程之外的线程访问。 - Diogo Kollross
1
如上所述,线程安全在这里不是问题,因为您为每个调用创建了一个StringBuffer实例,并且没有与任何其他线程共享它。这应该更改为StringBuilder - Gray
2
有没有不使用 getRequestURI 的理由? - Christophe Roussy

32

在Spring项目中,你可以使用

UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request)).build().toUriString()

4
为什么不这样做?new ServletServerHttpRequest(request).getURI() - Matt Sidesinger
URI不是URL。 - Enginer
最佳答案。喜欢这个一行代码。 - user674669
1
这是我今天看到的最令人满意的答案。即使微服务在网关后面链接也可以工作! - Houssem Chlegou
必须补充说明,UriComponentsBuilder不会添加“UriComponentsBuilder”,因此在网关下它并不能完美地工作。但是复制该方法仍然很好。 - Houssem Chlegou
这是唯一一个不操纵字符串的答案。 - Tamas Hegedus

28
// http://hostname.com/mywebapp/servlet/MyServlet/a/b;c=123?d=789

public static String getUrl(HttpServletRequest req) {
    String reqUrl = req.getRequestURL().toString();
    String queryString = req.getQueryString();   // d=789
    if (queryString != null) {
        reqUrl += "?"+queryString;
    }
    return reqUrl;
}

5
你忽略了StringBuffer的优势。 - BalusC
是的,我接受了,但我猜只有两个额外的对象。 - Teja Kantamneni
10
这里只是增加了一个对象(一个 StringBuilder),并且不会改变返回的底层 StringBuffer。我个人更喜欢这种方法,因为即使 JVM 优化这两种做法之间的差异,也不会有引入错误的风险。 - Ken Blair
(request.getRequestURL().toString() + ((request.getQueryString() != null) ? ("?" + request.getQueryString()) : "")) - Alex

7

HttpUtil已被弃用,这是正确的方法

StringBuffer url = req.getRequestURL();
String queryString = req.getQueryString();
if (queryString != null) {
    url.append('?');
    url.append(queryString);
}
String requestURL = url.toString();

5

如何处理相关的 POST 参数? - flash
3
严格来说,POST参数不是URL的一部分,它们是请求的主体(body)。 - Geert

2
你可以使用三元运算符编写一行简单的代码,如果你利用.getRequestURL()的StringBuffer构建器模式:
private String getUrlWithQueryParms(final HttpServletRequest request) { 
    return request.getQueryString() == null ? request.getRequestURL().toString() :
        request.getRequestURL().append("?").append(request.getQueryString()).toString();
}

"最初的回答"只是语法糖。

1
你让我感到开心。 - ahrooran

1
你可以使用筛选器。
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest test1=    (HttpServletRequest) arg0;
       
     test1.getRequestURL()); it gives  http://localhost:8081/applicationName/menu/index.action
     test1.getRequestURI()); it gives applicationName/menu/index.action
     String pathname = test1.getServletPath()); it gives //menu/index.action
      
  
    if(pathname.equals("//menu/index.action")){ 
        arg2.doFilter(arg0, arg1); // call to urs servlet or frameowrk managed controller method


       // in resposne 
       HttpServletResponse httpResp = (HttpServletResponse) arg1;
       RequestDispatcher rd = arg0.getRequestDispatcher("another.jsp");     
       rd.forward(arg0, arg1);
}

不要忘记在web.xml的过滤器映射中添加<dispatcher>FORWARD</dispatcher>

记录一下...test1.getRequestURI());它会返回/applicationName/menu/index.action(即它包含前导斜杠) - Stevko

1
使用HttpServletRequest对象上的以下方法
java.lang.String getRequestURI() - 返回此请求的URL的一部分,从协议名称到HTTP请求第一行中的查询字符串。
java.lang.StringBuffer getRequestURL() - 重构客户端用于发出请求的URL。
java.lang.String getQueryString() - 返回路径后包含在请求URL中的查询字符串。

0

我有一个使用案例,需要从httpServletRequest实例生成cURL命令(我可以在终端中使用)。 我创建了一个像这样的方法。 您可以直接复制此方法的输出并在终端中使用。

private StringBuilder generateCURL(final HttpServletRequest httpServletRequest) {
    final StringBuilder curlCommand = new StringBuilder();
    curlCommand.append("curl ");

    // iterating over headers.
    for (Enumeration<?> e = httpServletRequest.getHeaderNames(); e.hasMoreElements();) {
        String headerName = (String) e.nextElement();
        String headerValue = httpServletRequest.getHeader(headerName);
        // skipping cookies, as we're appending cookies separately.
        if (Objects.equals(headerName, "cookie")) {
            continue;
        }
        if (headerName != null && headerValue != null) {
            curlCommand.append(String.format(" -H \"%s:%s\" ", headerName, headerValue));
        }
    }

    // iterating over cookies.
    final Cookie[] cookieArray = httpServletRequest.getCookies();
    final StringBuilder cookies = new StringBuilder();
    for (Cookie cookie : cookieArray) {
        if (cookie.getName() != null && cookie.getValue() != null) {
            cookies.append(cookie.getName());
            cookies.append('=');
            cookies.append(cookie.getValue());
            cookies.append("; ");
        }
    }
    curlCommand.append(" --cookie \"" + cookies.toString() + "\"");

    // appending request url.
    curlCommand.append(" \"" + httpServletRequest.getRequestURL().toString() + "\"");
    return curlCommand;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接