向 Web 发出 GET 请求时不支持 415 内容类型 API

415 Content type not support when making GET request to Web API

我遇到了一个奇怪的问题,我的一个 API 端点在发出 GET 请求时因 415 Content type not supported 失败,我正在努力寻找原因.

更奇怪的是它在 Postman 中工作得很好。

它与我需要做的 URL 重写有关,因此我可以将请求路由到适当的服务器。如果我不重写,它也可以。

重定向代码非常基础,它只是获取请求的标识和服务器地址。对于上下文,我需要根据 GDPR 合规性的请求设置路由到不同的服务器。如果有人有更好的方法,我会洗耳恭听。

public class ProxyHandler : DelegatingHandler
    {
        private async Task<HttpResponseMessage> RedirectRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var identity = await GetIdentityAsync(request) as ParsedIdentity;

            using (var client = new HttpClient())
            {
                var clonedRequest = await request.CloneAsync();

                clonedRequest.RequestUri = new Uri(identity.Server.ApiUri + request.RequestUri.PathAndQuery);

                return await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
            }
        }

///Clone Async Extension
public static async Task<HttpRequestMessage> CloneAsync(this HttpRequestMessage req)
        {
            HttpRequestMessage clone = new HttpRequestMessage(req.Method, req.RequestUri);

            if (req.Content.Headers.ContentLength != null && req.Content.Headers.ContentLength > 0)
            {
                var contentStream = new StreamReader(await req.Content.ReadAsStreamAsync().ConfigureAwait(false));

                contentStream.BaseStream.Seek(0, SeekOrigin.Begin);

                clone.Content = new StreamContent(contentStream.BaseStream);

                // Copy the content headers
                if (req.Content.Headers != null)
                    foreach (var h in req.Content.Headers)
                        clone.Content.Headers.Add(h.Key, h.Value);
            }


            clone.Version = req.Version;

            foreach (KeyValuePair<string, object> prop in req.Properties)
                clone.Properties.Add(prop);

            foreach (KeyValuePair<string, IEnumerable<string>> header in req.Headers)
                clone.Headers.TryAddWithoutValidation(header.Key, header.Value);

            return clone;
        }

我已逐步完成代码并观察到它到达了预期的服务器、进行了身份验证并检查了 RouteData 以确保它是正确的控制器和方法。我已经检查以确保该方法是 GET 并且没有请求正文。一切都是正确的。但是,一旦它将请求传递给控制器​​,它就不会到达它并且 returns 415 Content type not supported

我什至完全重新创建了一个新请求,而不是克隆它(针对这个特定请求),它仍然这样做。

更奇怪的是,到目前为止,我只发现了一个执行此操作的请求。每隔 GET、POST、PUT、PATCH、DELETE 都有效。只有这个请求失败了。这让我发疯。特别是它适用于 Postman。

感谢任何帮助,我花了太多时间试图解决这个问题。

Request
{
    "Method": "GET",
    "Url": "http://localhost:4201/site/en-us/menus/7aa17e5d-d500-4ee7-889e-66cad2f3057e?menuTypes=all,main-nav",
    "ServerVariables": "HTTP/1.1",
    "RequestGuid": "bc5a4bfb-09f4-4e7d-bee1-19774d6aae6d",
    "header_Connection": "Close",
    "header_Accept": "application/json",
    "header_Accept-Encoding": "gzip, deflate, br",
    "header_Accept-Language": "en-US, en; q=0.9",
    "header_Authorization": "my-token",
    "header_Host": "localhost:44358",
    "header_Referer": "http://localhost:4200/",
    "header_User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36 Edg/100.0.1185.44",
    "header_sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Microsoft Edge\";v=\"100\"",
    "header_sec-ch-ua-mobile": "?0",
    "header_sec-ch-ua-platform": "\"Windows\"",
    "header_origin": "http://localhost:4200",
    "header_sec-fetch-site": "cross-site",
    "header_sec-fetch-mode": "cors",
    "header_sec-fetch-dest": "empty",
    "_env": "local"
}```

我已经解决了这个问题,但是我仍然不确定到底是什么问题,所以如果有人能回答,我将不胜感激。

我想指出,这个 API 已经在没有 URL 重写的生产系统中使用了大约 3 年,并且在浏览器或 Postman 中运行良好。此问题仅在通过代理来自浏览器时出现。

为了修复它,我更改了:

public async Task<HttpResponseMessage> GetMenus(Guid siteFirmUuid, string[] menuTypes, string locale = "en-us")

收件人:

public async Task<HttpResponseMessage> GetMenus(Guid siteFirmUuid, [FromUri]string[] menuTypes, string locale = "en-us")

我知道参数绑定是如何工作的,但我只是不明白为什么它在 Postman 中有效,在直接从站点调用时有效,但在缺少 FromUri 属性时从通过代理的站点失败。

此时,我很高兴它已修复,但我非常想知道是否有人可以帮助我弄清楚为什么这只在我上面描述的特定实例中失败。