【问题标题】:How to set up Web API Routing for a Proxy Controller?如何为代理控制器设置 Web API 路由?
【发布时间】:2018-03-29 14:21:15
【问题描述】:

我的应用程序的一部分需要充当第三方 RESTful Web 服务的代理服务器。有没有办法设置 Web API 路由,以便所有相同类型的请求都转到相同的方法?

例如,如果客户端发送这些 GET 请求中的任何一个,我希望它们进入单个 GET 操作方法,然后将请求发送到下游服务器。

api/Proxy/Customers/10045
api/Proxy/Customers/10045/orders
api/Proxy/Customers?lastname=smith

GET 的单一操作方法会获取这三个请求中的任何一个并将它们发送到相应的服务(我知道如何使用 HttpClient 来有效地实现这一点):

http://otherwebservice.com/Customers/10045
http://otherwebservice.com/Customers/10045/orders
http://otherwebservice.com/Customers?lastname=smith

我不想将我的 Web 服务与第三方 Web 服务紧密耦合,并将它们的整个 API 复制为我内部的方法调用。

我想到的一种解决方法是在客户端上用 JavaScript 对目标 URL 进行简单编码,然后将其传递给 Web API,然后它只会看到一个参数。它会起作用,但如果可能的话,我更喜欢使用 Web API 中的路由功能。

【问题讨论】:

  • 你有没有想过这个问题?我正在尝试做同样的事情。
  • 还没有。我觉得我已经接近了参数路由。
  • 我让它满足我的需求 - 请参阅发布的答案。

标签: asp.net-web-api proxy


【解决方案1】:

这是我如何让它工作的。首先,为您要支持的每个动词创建一个带有方法的控制器:

public class ProxyController : ApiController
{
    private Uri _baseUri = new Uri("http://otherwebservice.com");

    public async Task<HttpResponseMessage> Get(string url)
    {
    }

    public async Task<HttpResponseMessage> Post(string url)
    {
    }

    public async Task<HttpResponseMessage> Put(string url)
    {
    }

    public async Task<HttpResponseMessage> Delete(string url)
    {
    }
}

这些方法是异步的,因为它们将使用 HttpClient。像这样映射您的路线:

config.Routes.MapHttpRoute(
  name: "Proxy",
  routeTemplate: "api/Proxy/{*url}",
  defaults: new { controller = "Proxy" });

现在回到控制器中的 Get 方法。创建一个 HttpClient 对象,使用适当的 Url 创建一个新的 HttpRequestMessage 对象,从原始请求消息中复制所有内容(或几乎所有内容),然后调用 SendAsync():

public async Task<HttpResponseMessage> Get(string url)
{
    using (var httpClient = new HttpClient())         
    {
        string absoluteUrl = _baseUri.ToString() + "/" + url + Request.RequestUri.Query;
        var proxyRequest = new HttpRequestMessage(Request.Method, absoluteUrl);
        foreach (var header in Request.Headers)
        {
            proxyRequest.Headers.Add(header.Key, header.Value);
        }

        return await httpClient.SendAsync(proxyRequest, HttpCompletionOption.ResponseContentRead);
    }
}

结合could be more sophisticated的URL,但这是基本思想。 对于 Post 和 Put 方法,您还需要复制请求正文

另外请注意在SendAsync调用中传递的HttpCompletionOption.ResponseContentRead参数,因为没有它,如果内容很大,ASP.NET将花费很长时间读取内容(在我的例子中,它改变了一个500KB 100ms的请求进入 60 年代的请求)。

【讨论】:

  • 嗯...似乎不适用于查询参数。仍在努力。
  • 很难实现这个...原因是标题的复制。删除 foreach 后,一切正常。
  • @NoRyb 复制标头给您带来了什么麻烦?
  • @NoRyb 当中继到另一个域时,我唯一的问题来自带有 TSL 的主机标头。当我留下未复制的内容时,一切正常。你遇到了什么问题?
  • 如果请求包含 Host 标头,请小心。看起来 HttpClient 将用主机头的内容替换 Uri 的基本部分。这可能会导致 http 调用被定向到另一个服务器,而不是您请求它的位置。
猜你喜欢
  • 1970-01-01
  • 2015-05-04
  • 1970-01-01
  • 2015-12-28
  • 2023-04-01
  • 2016-08-03
  • 1970-01-01
  • 2015-04-06
  • 1970-01-01
相关资源
最近更新 更多