首页 > 解决方案 > 我可以使用 Ocelot 将 POST http 请求重新路由到 GET http 请求吗?

问题描述

我们有一个 ocelot 网关,可以将我们以前的 WCF 请求重新路由到更新的 .NET Core 服务。一些旧请求仍将发送到 WCF 服务。这一切都很好。

现在我想将带有请求模型的 POST重新路由到带有查询字符串标头的 GET 。我似乎无法弄清楚如何做到这一点,所以我有点期望查询字符串参数能够开箱即用并为标题做一些自定义的事情。

这是我的重新路由json:

{
      "DownstreamPathTemplate": "/v1/attachments",
      "DownstreamScheme": "http",
      "DownstreamHttpMethod": [ "GET" ],
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 53737
        }
      ],
      "UpstreamPathTemplate": "/mobile/ImageService.svc/json/GetImage",
      "UpstreamHttpMethod": [ "POST" ],
      "UpstreamHost": "*"
    }

我的请求正文:

{
    "SessionId":"XXX", //needs to be a header
    "ImageId": "D13XXX", //needs to be added to query string
    "MaxWidth" : "78", //needs to be added to query string
    "MaxHeight" : "52", //needs to be added to query string
    "EditMode": "0" //needs to be added to query string
}

是否可以在 ocelot 中配置它以便正确重新路由?如果是这样,你能指出我正确的方向吗?

标签: c#.netrestwcfocelot

解决方案


我认为这就是你需要的 https://ocelot.readthedocs.io/en/latest/features/delegatinghandlers.html

我没有检查您是否更改了 http 动词等,但我猜您可以将查询字符串参数添加到转发请求中(您将收到 http 请求消息)。我认为你应该能够做几乎任何你喜欢的事情!

这是您可以实现的代码类型的未经测试的示例

public class PostToGetHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Only want to do this if it matches our route
        // See section later on about global or route specific handlers
        if (request.RequestUri.OriginalString.Contains("/mobile/ImageService.svc/json/GetImage") && request.Method.Equals(HttpMethod.Post))
        {
            var bodyString = await request.Content.ReadAsStringAsync();

            // Deserialize into a MyClass that will hold your request body data
            var myClass = JsonConvert.DeserializeObject<MyClass>(bodyString);

            // Append your querystrings
            var builder = new QueryBuilder();
            builder.Add("ImageId", myClass.ImageId);
            builder.Add("MaxWidth", myClass.MaxWidth);      // Keep adding queryString values

            // Build a new uri with the querystrings
            var uriBuilder = new UriBuilder(request.RequestUri);
            uriBuilder.Query = builder.ToQueryString().Value;

            // TODO - Check if querystring already exists etc
            request.RequestUri = uriBuilder.Uri;

            // Add your header - TODO - Check to see if this header already exists
            request.Headers.Add("SessionId", myClass.SessionId.ToString());

            // Get rid of the POST content
            request.Content = null;
        }

        // On it goes either amended or not
        // Assumes Ocelot will change the verb to a GET as part of its transformation
        return await base.SendAsync(request, cancellationToken);
    }
}

在Ocelot启动中可以这样注册

services.AddDelegatingHandler<PostToGetHandler>();

或者

services.AddDelegatingHandler<PostToGetHandler>(true);  // Make it global

这些处理程序可以是全局的或特定于路由的(因此,如果您将其设为特定于路由,则可能不需要在上面的代码中进行路由检查)

这是来自 Ocelot 文档:

最后,如果您想要 ReRoute 特定的 DelegatingHandlers 或订购特定的和/或全局的(稍后会详细介绍)DelegatingHandlers,那么您必须将以下 json 添加到 ocelot.json 中的特定 ReRoute。数组中的名称必须与您的 DelegatingHandlers 的类名称匹配,以便 Ocelot 将它们匹配在一起。

"DelegatingHandlers": [
    "PostToGetHandler"
]

我建议最初向您的 Ocelot 实例添加一个简单的处理程序,然后对其进行测试并添加以使其执行您想要的操作。我希望这对您想做的事情有所帮助。


推荐阅读