【问题标题】:HttpServletRequest to complete URLHttpServletRequest 完成 URL
【发布时间】:2011-01-14 09:37:02
【问题描述】:

我有一个HttpServletRequest 对象。

如何获取导致此调用到达我的 servlet 的完整且准确的 URL?

或者至少尽可能准确,因为也许有些东西可以重新生成(也许是参数的顺序)。

【问题讨论】:

标签: java http servlets


【解决方案1】:

HttpServletRequest有以下方法:

  • getRequestURL() - 返回查询字符串分隔符 ? 之前的完整 URL 部分
  • getQueryString() - 返回查询字符串分隔符 ? 之后的完整 URL 部分

所以,要获取完整的 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();
    }
}

【讨论】:

  • 您从 getRequestURI 复制了描述(错误),但在代码中使用了 getRequestURL(正确)。
  • 需要有条件地检查查询字符串是否为空。
  • 你也在改变支持请求 URL 的 StringBuffer。如果请求实现没有制作防御性副本,那么这是在其他期望以原始形式出现的代码部分引入奇怪行为和错误的好方法。
  • 使用 StringBuilder 代替 StringBuffer
  • @KenBlair:故意返回一个 StringBuffer,以便您可以轻松添加更多存储。由于这是在 javadoc 中指定的,因此期望返回的 StringBuffer 不会被调用者修改是非常荒谬的 - 因此,这很酷。
【解决方案2】:

结合getRequestURL()getQueryString() 的结果应该可以得到你想要的结果。

【讨论】:

  • 如何处理post相关参数?
  • @flash 严格来说,POST 参数不是 URL 的一部分,它们是请求的 body
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:
    // 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;
    }
    

    【讨论】:

    • 你忽略了StringBuffer的优势。
    • 是的。我接受它,但我猜它只有两个额外的对象。
    • 它是 一个 附加对象(一个 StringBuilder),不会改变返回的底层 StringBuffer。我实际上更喜欢这个而不是“接受”的答案,JVM 将优化差异,无论如何这不会有任何引入错误的风险。
    • (request.getRequestURL().toString() + ((request.getQueryString() != null) ? ("?" + request.getQueryString()) : ""))
    【解决方案5】:

    我用这个方法:

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

    【讨论】:

    • 这是快速参考 HttpServletRequest 上所有可用信息的有用答案。但是,我认为您在决定是否将端口块添加到结果时需要检查该方案。例如,“https”将是 443。
    • 一个小的优化是使用StringBuilder而不是StringBuffer,只是一个提示
    • 只是注释:在这个特定示例中线程安全不是问题,因为url 仅在方法内部声明、实例化和使用,因此不能从除调用该方法的那个。
    • 如前所述,线程安全在这里不是问题,因为您正在为每次调用创建StringBuffer 的实例,而不是与任何其他线程共享它。这应该改为StringBuilder
    • 有什么理由不使用getRequestURI
    【解决方案6】:

    您可以使用过滤器。

    @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);
    
    
    
    
    
        }
    

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

    【讨论】:

    • 备案...test1.getRequestURI());它给出 /applicationName/menu/index.action (即它包含前导斜杠)
    【解决方案7】:

    对 HttpServletRequest 对象使用以下方法

    java.lang.String getRequestURI() - 返回此请求的 URL 中从协议名称到 HTTP 请求第一行中的查询字符串的部分。

    java.lang.StringBuffer getRequestURL() - 重构客户端用于发出请求的 URL。

    java.lang.String getQueryString() - 返回路径后面的请求 URL 中包含的查询字符串。

    【讨论】:

      【解决方案8】:

      在 Spring 项目中你可以使用

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

      【讨论】:

      • 为什么不呢? new ServletServerHttpRequest(request).getURI()
      • URI 它不是 URL
      • 最佳答案。喜欢单线。
      • 这是我今天看到的最满意的答案。即使微服务链接在网关后面也能正常工作!
      • 必须添加,UriComponentsBuilder没有添加“UriComponentsBuilder”,所以在网关下不能完美运行。但还是很高兴复制该方法。
      【解决方案9】:

      聚会有点晚了,但我在WebUtils 中的MarkUtils-Web library 中包含了这个 - Checkstyle-approved 和 JUnit-tested:

      import javax.servlet.http.HttpServletRequest;
      
      public class GetRequestUrl{
          /**
           * <p>A faster replacement for {@link HttpServletRequest#getRequestURL()}
           *  (returns a {@link String} instead of a {@link StringBuffer} - and internally uses a {@link StringBuilder})
           *  that also includes the {@linkplain HttpServletRequest#getQueryString() query string}.</p>
           * <p><a href="https://gist.github.com/ziesemer/700376d8da8c60585438"
           *  >https://gist.github.com/ziesemer/700376d8da8c60585438</a></p>
           * @author Mark A. Ziesemer
           *  <a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a>
           */
          public String getRequestUrl(final HttpServletRequest req){
              final String scheme = req.getScheme();
              final int port = req.getServerPort();
              final StringBuilder url = new StringBuilder(256);
              url.append(scheme);
              url.append("://");
              url.append(req.getServerName());
              if(!(("http".equals(scheme) && (port == 0 || port == 80))
                      || ("https".equals(scheme) && port == 443))){
                  url.append(':');
                  url.append(port);
              }
              url.append(req.getRequestURI());
              final String qs = req.getQueryString();
              if(qs != null){
                  url.append('?');
                  url.append(qs);
              }
              final String result = url.toString();
              return result;
          }
      }
      

      可能是迄今为止最快和最可靠的答案,仅次于 Mat Banik 的答案 - 但即使是他的答案也没有考虑到 HTTP/HTTPS 的潜在非标准端口配置。

      另见:

      【讨论】:

        【解决方案10】:

        如果您使用来自.getRequestURL() 的StringBuffer 的构建器模式,您可以编写一个简单的带有三元的单行器:

        private String getUrlWithQueryParms(final HttpServletRequest request) { 
            return request.getQueryString() == null ? request.getRequestURL().toString() :
                request.getRequestURL().append("?").append(request.getQueryString()).toString();
        }
        

        但这只是语法糖。

        【讨论】:

          【解决方案11】:

          当请求被转发时,例如从反向代理中,HttpServletRequest.getRequestURL() 方法不会返回转发的 url,而是返回本地 url。 设置x-forwarded-* Headers 后,就可以轻松处理:

          public static String getCurrentUrl(HttpServletRequest request) {
              String forwardedHost = request.getHeader("x-forwarded-host");
          
              if(forwardedHost == null) {
                  return request.getRequestURL().toString();
              }
          
              String scheme = request.getHeader("x-forwarded-proto");
              String prefix = request.getHeader("x-forwarded-prefix");
          
              return scheme + "://" + forwardedHost + prefix + request.getRequestURI();
          }
          

          这缺少查询部分,但可以按照其他答案中的假设附加。我来这里是因为我特别需要那些转发的东西,希望能帮助别人。

          【讨论】:

            猜你喜欢
            • 2014-07-04
            • 1970-01-01
            • 2012-08-23
            • 1970-01-01
            • 1970-01-01
            • 2020-02-11
            • 2011-02-08
            • 1970-01-01
            • 2010-11-18
            相关资源
            最近更新 更多