如何让 Url.Action 使用正确的端口号?

发布于 2024-12-10 09:16:05 字数 1330 浏览 0 评论 0 原文

我正在使用 MVC3 创建一个网站,我使用 razor 语法来创建视图,并且所有这些都在 azure 下运行。

目前我在本地的azure模拟器下运行。

我在网址上有一个视图:'http://localhost:81/Blah/Foo'。

在该视图中,我想获取另一个操作的 Url。

为了实现这一点,我使用: Url.Action("SomeAction", "SomeController", null, this.Request.Url.Scheme)

但是,由于负载平衡,azure 模拟器会更改请求的端口号。

即,当它在端口 81 上运行时,请求可能来自端口 82。

这会导致创建不正确的 url 'http: //localhost:82/Blah/Bar',我收到 400 错误主机名错误。

按照这篇文章中的信息http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9142db8d-0f85-47a2-91f7-418bb5a0c675/ 我发现我可以获得正确的结果使用 HttpContext.Request.Headers["Host"] 的主机和端口号。

但我只能将主机名传递给 Url.Action,如果我尝试传递主机名和端口,那么它仍然会附加它认为正确的端口,所以我最终会得到 localhost:81:82。

编辑:我发现有人有同样的问题。他们似乎收集了与我相同的信息(除了他们也包含了复制品),但他们没有有用的修复,因为我无法手动指定端口号。

http://social.msdn.microsoft.com/Forums/en-US/windowsazuredevelopment/thread/87c729e8-094c-4578-b9d1-9c8ff7311577/

我想一个解决办法是我自己的 Url.Action 重载让我可以指定端口。

I'm creating a website using MVC3, I'm using the razor syntax to create the views and it's all running under azure.

Currently I'm running under the azure emulator locally.

I have a view at the url: 'http://localhost:81/Blah/Foo'.

In that view I want to get the Url for another action.

To achieve this I use: Url.Action("SomeAction", "SomeController", null, this.Request.Url.Scheme)

However because of the load balancing the azure emulator does the port number the request is made on changes.

i.e. whilst it's running on port 81, the request might come from port 82.

This leads to to create an incorrect url 'http://localhost:82/Blah/Bar' and I get a 400, bad hostname error.

Following the info in this post http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/9142db8d-0f85-47a2-91f7-418bb5a0c675/ I found that I could get the correct host and port number using HttpContext.Request.Headers["Host"].

But I can only pass a host-name to Url.Action, if I try passing the host-name and port then it still appends what it thinks is the right port so I end up with localhost:81:82.

EDIT: I found someone with the same problem. They seem to have gathered the same information I have (except they've included a reproduction too) but they don't have a useful fix as I can't specify the port number manually.

http://social.msdn.microsoft.com/Forums/en-US/windowsazuredevelopment/thread/87c729e8-094c-4578-b9d1-9c8ff7311577/

I suppose one fix would be to make my own Url.Action overload that lets me specify the port.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

末が日狂欢 2024-12-17 09:16:05

对于来到这里的每个实际上需要绝对路径并且支持负载平衡系统的人,这就是我想到的:

//http://stackoverflow.com/questions/126242/how-do-i-turn-a-relative-url-into-a-full-url
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, object routeValues = null)
{
  Uri publicFacingUrl = GetPublicFacingUrl(url.RequestContext.HttpContext.Request, url.RequestContext.HttpContext.Request.ServerVariables);
  string relAction = url.Action(actionName, controllerName, routeValues);
  //this will always have a / in front of it.
  var newPort = publicFacingUrl.Port == 80 || publicFacingUrl.Port == 443 ? "" : ":"+publicFacingUrl.Port.ToString();
  return publicFacingUrl.Scheme + Uri.SchemeDelimiter + publicFacingUrl.Host + newPort + relAction;
}

然后,来自 https://github.com/aarnott/dotnetopenid/blob/v3.4/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs 通过 http://go4answers.webhost4life.com/Example/azure-messing-port-numbers-creates-28516.aspx

   /// <summary>
    /// Gets the public facing URL for the given incoming HTTP request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <param name="serverVariables">The server variables to consider part of the request.</param>
    /// <returns>
    /// The URI that the outside world used to create this request.
    /// </returns>
    /// <remarks>
    /// Although the <paramref name="serverVariables"/> value can be obtained from
    /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
    /// in so we can simulate injected values from our unit tests since the actual property
    /// is a read-only kind of <see cref="NameValueCollection"/>.
    /// </remarks>
internal static Uri GetPublicFacingUrl(HttpRequestBase request, NameValueCollection serverVariables)
{
  //Contract.Requires<ArgumentNullException>(request != null);
  //Contract.Requires<ArgumentNullException>(serverVariables != null);

  // Due to URL rewriting, cloud computing (i.e. Azure)
  // and web farms, etc., we have to be VERY careful about what
  // we consider the incoming URL.  We want to see the URL as it would
  // appear on the public-facing side of the hosting web site.
  // HttpRequest.Url gives us the internal URL in a cloud environment,
  // So we use a variable that (at least from what I can tell) gives us
  // the public URL:
  if (serverVariables["HTTP_HOST"] != null)
  {
    //ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
    string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
    Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
    UriBuilder publicRequestUri = new UriBuilder(request.Url);
    publicRequestUri.Scheme = scheme;
    publicRequestUri.Host = hostAndPort.Host;
    publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port
    return publicRequestUri.Uri;
  }
  // Failover to the method that works for non-web farm enviroments.
  // We use Request.Url for the full path to the server, and modify it
  // with Request.RawUrl to capture both the cookieless session "directory" if it exists
  // and the original path in case URL rewriting is going on.  We don't want to be
  // fooled by URL rewriting because we're comparing the actual URL with what's in
  // the return_to parameter in some cases.
  // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
  // session, but not the URL rewriting problem.
  return new Uri(request.Url, request.RawUrl);
}

For everyone coming here who actually NEEDS an absolute path and are behind a load balanced system, here's what I came up with:

//http://stackoverflow.com/questions/126242/how-do-i-turn-a-relative-url-into-a-full-url
public static string AbsoluteAction(this UrlHelper url, string actionName, string controllerName, object routeValues = null)
{
  Uri publicFacingUrl = GetPublicFacingUrl(url.RequestContext.HttpContext.Request, url.RequestContext.HttpContext.Request.ServerVariables);
  string relAction = url.Action(actionName, controllerName, routeValues);
  //this will always have a / in front of it.
  var newPort = publicFacingUrl.Port == 80 || publicFacingUrl.Port == 443 ? "" : ":"+publicFacingUrl.Port.ToString();
  return publicFacingUrl.Scheme + Uri.SchemeDelimiter + publicFacingUrl.Host + newPort + relAction;
}

And then, from https://github.com/aarnott/dotnetopenid/blob/v3.4/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs via http://go4answers.webhost4life.com/Example/azure-messing-port-numbers-creates-28516.aspx

   /// <summary>
    /// Gets the public facing URL for the given incoming HTTP request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <param name="serverVariables">The server variables to consider part of the request.</param>
    /// <returns>
    /// The URI that the outside world used to create this request.
    /// </returns>
    /// <remarks>
    /// Although the <paramref name="serverVariables"/> value can be obtained from
    /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
    /// in so we can simulate injected values from our unit tests since the actual property
    /// is a read-only kind of <see cref="NameValueCollection"/>.
    /// </remarks>
internal static Uri GetPublicFacingUrl(HttpRequestBase request, NameValueCollection serverVariables)
{
  //Contract.Requires<ArgumentNullException>(request != null);
  //Contract.Requires<ArgumentNullException>(serverVariables != null);

  // Due to URL rewriting, cloud computing (i.e. Azure)
  // and web farms, etc., we have to be VERY careful about what
  // we consider the incoming URL.  We want to see the URL as it would
  // appear on the public-facing side of the hosting web site.
  // HttpRequest.Url gives us the internal URL in a cloud environment,
  // So we use a variable that (at least from what I can tell) gives us
  // the public URL:
  if (serverVariables["HTTP_HOST"] != null)
  {
    //ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
    string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
    Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
    UriBuilder publicRequestUri = new UriBuilder(request.Url);
    publicRequestUri.Scheme = scheme;
    publicRequestUri.Host = hostAndPort.Host;
    publicRequestUri.Port = hostAndPort.Port; // CC missing Uri.Port contract that's on UriBuilder.Port
    return publicRequestUri.Uri;
  }
  // Failover to the method that works for non-web farm enviroments.
  // We use Request.Url for the full path to the server, and modify it
  // with Request.RawUrl to capture both the cookieless session "directory" if it exists
  // and the original path in case URL rewriting is going on.  We don't want to be
  // fooled by URL rewriting because we're comparing the actual URL with what's in
  // the return_to parameter in some cases.
  // Response.ApplyAppPathModifier(builder.Path) would have worked for the cookieless
  // session, but not the URL rewriting problem.
  return new Uri(request.Url, request.RawUrl);
}
双手揣兜 2024-12-17 09:16:05

如果你只使用 Url.Action("Action", "Controller") 会发生什么?这应该只是生成一个相对 URL,它应该可以工作。

(或者也许更好的问题是:你为什么不使用那个重载?)

What happens if you just use Url.Action("Action", "Controller")? That should just generate a relative URL, which should work.

(Or perhaps a better question is: why aren't you using that overload?)

濫情▎り 2024-12-17 09:16:05

我发现这对我有用......

var request = HttpContext.Request;
string url = request.Url.Scheme + "://" +
             request.UserHostAddress +  ":" +
             request.Url.Port;

I found this worked for me...

var request = HttpContext.Request;
string url = request.Url.Scheme + "://" +
             request.UserHostAddress +  ":" +
             request.Url.Port;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文