【问题标题】:Get Absolute URL from Relative path (refactored method)从相对路径获取绝对 URL(重构方法)
【发布时间】:2011-04-10 12:16:13
【问题描述】:

我真的很惊讶没有本地 .NET 方法可以从相对 url 获取绝对 url。我知道这已经讨论过很多次了,但从来没有遇到过能很好地处理这个问题的令人满意的方法。你能帮忙微调下面的方法吗?

我认为我只需要自动选择协议而不是硬编码(http/https)。我还缺少什么(注意事项、性能等)?

public static string GetAbsoluteUrl(string url)
    {
        //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
        if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) 
           || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        { 
            return url;
        }

        //GET PAGE REFERENCE FOR CONTEXT PROCESSING
        Page page = HttpContext.Current.Handler as Page;

        //RESOLVE PATH FOR APPLICATION BEFORE PROCESSING
        if (url.StartsWith("~/"))
        {
            url = page.ResolveUrl(url);
        }

        //BUILD AND RETURN ABSOLUTE URL
        return "http://" + page.Request.ServerVariables["SERVER_NAME"] + "/" 
                         + url.TrimStart('/');
    }

【问题讨论】:

  • 对您的代码的一点建议。您应该使用 String.Format 而不是最后连接 URL 位。

标签: c# .net asp.net .net-3.5


【解决方案1】:

这一直是我处理这个小麻烦的方法。请注意,VirtualPathUtility.ToAbsolute(relativeUrl) 的使用允许将方法声明为静态类中的扩展。

/// <summary>
/// Converts the provided app-relative path into an absolute Url containing the 
/// full host name
/// </summary>
/// <param name="relativeUrl">App-Relative path</param>
/// <returns>Provided relativeUrl parameter as fully qualified Url</returns>
/// <example>~/path/to/foo to http://www.web.com/path/to/foo</example>
public static string ToAbsoluteUrl(this string relativeUrl) {
    if (string.IsNullOrEmpty(relativeUrl))
        return relativeUrl;

    if (HttpContext.Current == null)
        return relativeUrl;

    if (relativeUrl.StartsWith("/"))
        relativeUrl = relativeUrl.Insert(0, "~");
    if (!relativeUrl.StartsWith("~/"))
        relativeUrl = relativeUrl.Insert(0, "~/");

    var url = HttpContext.Current.Request.Url;
    var port = url.Port != 80 ? (":" + url.Port) : String.Empty;

    return String.Format("{0}://{1}{2}{3}",
        url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(relativeUrl));
}

【讨论】:

  • 快速说明.. 有时我不想要路径的根,而是我所在位置的根。像这样:Page.ResolveUrl("SomePage.aspx")。在你的方法中,这将假设我想要 ~/SomePage.aspx 而我真的想要 ~/path/to/where/I/currently/am/SomePage.aspx。好方法!
  • ..顺便说一句,VirtualPathUtility.ToAbsolute 要求您在开头有一个 ~ 。但是,如果我想要一个指向我所在位置的相对路径,那么 (context.Handler as Page).ResolveUrl 就可以了。
  • 嗯,我是如何创建这个社区 wiki 的? >.
  • 很好的方法,只是一个小修改,在 https "var port = url.Port == 80 || (url.Scheme == "https" && url.Port == 时不添加端口443)?“”:“:”+ url.Port;“
  • 旧帖,但我认为最好使用url.IsDefaultPort,而不是同时检查http和https实例的端口号。
【解决方案2】:
new System.Uri(Page.Request.Url, "/myRelativeUrl.aspx").AbsoluteUri

【讨论】:

  • 谢谢。这至少对于 Windows 应用商店应用非常有效。
  • 认为这应该是现在的答案.. 也适用于 Web 应用程序
  • 如果提供的相对 URL 实际上是绝对 URL,这似乎会失败。例如,new System.Uri("http://example.com", "http://google.com") 应该返回 google 链接。
  • 我不同意。这也适用于相对 url 是绝对的。但是,如果您的相对网址中有“~”,则它不起作用。
【解决方案3】:

这个对我有用...

new System.Uri(Page.Request.Url, ResolveClientUrl("~/mypage.aspx")).AbsoluteUri

【讨论】:

    【解决方案4】:

    对于 ASP.NET,您需要考虑“相对 URL”的参考点 - 它是相对于页面请求、用户控件还是仅通过使用“~/”而“相对” ?

    Uri 类包含一种将相对 URL 转换为绝对 URL 的简单方法(假设绝对 URL 作为相对 URL 的参考点):

    var uri = new Uri(absoluteUrl, relativeUrl);
    

    如果 relativeUrl 实际上是一个绝对 URL,则 absoluteUrl 将被忽略。

    唯一的问题是参考点是什么,以及是否允许使用“~/” URL(Uri 构造函数不会翻译这些)。

    【讨论】:

      【解决方案5】:

      这是我自己的版本,它处理来自用户当前位置选项的许多验证和相对路径。随意从这里重构:)

      /// <summary>
      /// Converts the provided app-relative path into an absolute Url containing 
      /// the full host name
      /// </summary>
      /// <param name="relativeUrl">App-Relative path</param>
      /// <returns>Provided relativeUrl parameter as fully qualified Url</returns>
      /// <example>~/path/to/foo to http://www.web.com/path/to/foo</example>
      public static string GetAbsoluteUrl(string relativeUrl)
      {
          //VALIDATE INPUT
          if (String.IsNullOrEmpty(relativeUrl))
              return String.Empty;
          //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
          if (relativeUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) 
          || relativeUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
              return relativeUrl;
          //VALIDATE CONTEXT
          if (HttpContext.Current == null)
              return relativeUrl;
          //GET CONTEXT OF CURRENT USER
          HttpContext context = HttpContext.Current;
          //FIX ROOT PATH TO APP ROOT PATH
          if (relativeUrl.StartsWith("/"))
              relativeUrl = relativeUrl.Insert(0, "~");
          //GET RELATIVE PATH
          Page page = context.Handler as Page;
          if (page != null)
          {
              //USE PAGE IN CASE RELATIVE TO USER'S CURRENT LOCATION IS NEEDED
              relativeUrl = page.ResolveUrl(relativeUrl);
          }
          else //OTHERWISE ASSUME WE WANT ROOT PATH
         {
              //PREPARE TO USE IN VIRTUAL PATH UTILITY
              if (!relativeUrl.StartsWith("~/"))
                  relativeUrl = relativeUrl.Insert(0, "~/");
              relativeUrl = VirtualPathUtility.ToAbsolute(relativeUrl);
          }
      
          var url = context.Request.Url;
          var port = url.Port != 80 ? (":" + url.Port) : String.Empty;
          //BUILD AND RETURN ABSOLUTE URL
          return String.Format("{0}://{1}{2}{3}",
                 url.Scheme, url.Host, port, relativeUrl);
      }
      

      【讨论】:

        【解决方案6】:

        如果您在 MVC 控制器或视图的上下文中,您可以使用 UrlHelper,它应该可以通过 Url 访问

        Url.Content("~/content/images/myimage.jpg")
        

        这将完全扩展为/virtual_directoryname/content/images/myimage.jpg

        这可以在控制器或 .cshtml 文件中使用

        是的,它被称为 Content 有点奇怪,但它是用来获取资源的绝对路径的,所以它是有意义的

        【讨论】:

        • 这不是绝对网址。
        • 正确。这是根相对 URL。
        【解决方案7】:

        使用原生的东西仍然不够好。这是我最终得到的结果:

        public static string GetAbsoluteUrl(string url)
        {
            //VALIDATE INPUT
            if (String.IsNullOrEmpty(url))
            {
                return String.Empty;
            }
        
            //VALIDATE INPUT FOR ALREADY ABSOLUTE URL
            if (url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            { 
                return url;
            }
        
            //GET CONTEXT OF CURRENT USER
            HttpContext context = HttpContext.Current;
        
            //RESOLVE PATH FOR APPLICATION BEFORE PROCESSING
            if (url.StartsWith("~/"))
            {
                url = (context.Handler as Page).ResolveUrl(url);
            }
        
            //BUILD AND RETURN ABSOLUTE URL
            string port = (context.Request.Url.Port != 80 && context.Request.Url.Port != 443) ? ":" + context.Request.Url.Port : String.Empty;
            return context.Request.Url.Scheme + Uri.SchemeDelimiter + context.Request.Url.Host + port + "/" + url.TrimStart('/');
        }
        

        【讨论】:

          【解决方案8】:

          当您想从业务逻辑层生成 URL 时,您没有使用 ASP.NET Web 窗体的 Page 类/控件的 ResolveUrl(..) 等的灵活性。此外,您可能需要从 ASP.NET MVC 控制器,你不仅错过了 Web 窗体的 ResolveUrl(..) 方法,而且即使 Url.Action 只需要控制器名称和操作,你也无法获取 Url.Action(..)名称,而不是相对 url。

          我尝试过使用

          var uri = new Uri(absoluteUrl, relativeUrl)

          方法,但也有问题。如果 Web 应用程序托管在 IIS 虚拟目录中,其中应用程序的 url 是这样的:http://localhost/MyWebApplication1/,并且相对 url 是“/myPage”,那么相对 url 被解析为“http://localhost/MyPage”,这是另一个问题.

          因此,为了克服这些问题,我编写了一个可以在类库中工作的 UrlUtils 类。因此,它不依赖于 Page 类,而是依赖于 ASP.NET MVC。因此,如果您不介意在您的类库项目中添加对 MVC dll 的引用,那么我的课程将顺利进行。我已经在 IIS 虚拟目录场景中进行了测试,其中 Web 应用程序 url 是这样的:http://localhost/MyWebApplication/MyPage。我意识到,有时我们需要确保绝对 url 是 SSL url 或非 SSL url。因此,我编写了支持此选项的类库。我已经限制了这个类库,以便相对 url 可以是绝对 url 或以“~/”开头的相对 url。

          使用这个库,我可以调用

          string absoluteUrl = UrlUtils.MapUrl("~/Contact");
          

          返回:http://localhost/Contact 当页面 url 为:http://localhost/Home/About

          返回:http://localhost/MyWebApplication/Contact 当页面 url 为:http://localhost/MyWebApplication/Home/About

            string absoluteUrl = UrlUtils.MapUrl("~/Contact", UrlUtils.UrlMapOptions.AlwaysSSL);
          

          返回:**https**://localhost/MyWebApplication/Contact 当页面 url 为:http://localhost/MyWebApplication/Home/About

          这是我的类库:

           public class UrlUtils
              {
                  public enum UrlMapOptions
                  {
                      AlwaysNonSSL,
                      AlwaysSSL,
                      BasedOnCurrentScheme
                  }
          
                  public static string MapUrl(string relativeUrl, UrlMapOptions option = UrlMapOptions.BasedOnCurrentScheme)
                  {
                      if (relativeUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
                          relativeUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
                          return relativeUrl;
          
                      if (!relativeUrl.StartsWith("~/"))
                          throw new Exception("The relative url must start with ~/");
          
                      UrlHelper theHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
          
                      string theAbsoluteUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) +
                                                     theHelper.Content(relativeUrl);
          
                      switch (option)
                      {
                          case UrlMapOptions.AlwaysNonSSL:
                              {
                                  return theAbsoluteUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
                                      ? string.Format("http://{0}", theAbsoluteUrl.Remove(0, 8))
                                      : theAbsoluteUrl;
                              }
                          case UrlMapOptions.AlwaysSSL:
                              {
                                  return theAbsoluteUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
                                      ? theAbsoluteUrl
                                      : string.Format("https://{0}", theAbsoluteUrl.Remove(0, 7));
                              }
                      }
          
                      return theAbsoluteUrl;
                  }
              }   
          

          【讨论】:

            【解决方案9】:

            处理所有先前投诉的最终版本(端口、逻辑 url、相对 url、现有绝对 url...等)考虑当前处理程序是页面:

            public static string ConvertToAbsoluteUrl(string url)
            {
                if (!IsAbsoluteUrl(url))
                {
                    if (HttpContext.Current != null && HttpContext.Current.Request != null && HttpContext.Current.Handler is System.Web.UI.Page)
                    {
                        var originalUrl = HttpContext.Current.Request.Url;
                        return string.Format("{0}://{1}{2}{3}", originalUrl.Scheme, originalUrl.Host, !originalUrl.IsDefaultPort ? (":" + originalUrl.Port) : string.Empty, ((System.Web.UI.Page)HttpContext.Current.Handler).ResolveUrl(url));
                    }
                    throw new Exception("Invalid context!");
                }
                else
                    return url;
            }
            
            private static bool IsAbsoluteUrl(string url)
            {
                Uri result;
                return Uri.TryCreate(url, UriKind.Absolute, out result);
            }
            

            【讨论】:

              【解决方案10】:

              检查以下代码以检索绝对网址:

              Page.Request.Url.AbsoluteUri
              

              希望对你有用。

              【讨论】:

                【解决方案11】:

                这也很好用:

                HttpContext.Current.Server.MapPath(relativePath)
                

                相对路径类似于“~/foo/file.jpg”

                【讨论】:

                猜你喜欢
                • 2012-08-27
                • 1970-01-01
                • 2022-06-10
                • 2011-08-11
                • 2010-09-21
                • 2023-03-22
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多