【问题标题】:No request headers are being sent using .net-core没有使用 .net-core 发送请求标头
【发布时间】:2020-04-21 11:46:37
【问题描述】:

我正在编写一个 .NET 核心 web 服务(从现在开始我将把它称为“MyWs”),它应该触发另一个 web 服务的端点(从现在开始我将把它称为“OtherWs”)。使用邮递员向 OtherWs 发送请求时,一切正常。 但是,当我尝试从 MyWs 联系 OtherWs 时,我总是得到“未经授权”的响应 (401)。查看 Fiddler(我用来检查 http(s) 流量的工具)跟踪的请求,似乎 MyWs 实际上没有发送任何请求标头,即使它们在代码中进行了配置。

邮递员的配置方式可以在这个截图中看到: https://i.imgur.com/lclYoZT.png

Fiddler 中的请求可以在这里看到:https://imgur.com/pDDcgUbhttps://imgur.com/7cgIGKw

尽管这可行,但这里有两件奇怪的事情在起作用:

  1. 授权标头在 Fiddler 中不可见。但是,我确信授权标头起着重要作用,因为当我将其更改为错误值时,我会收到“未授权”响应 (401)。
  2. 尽管我只触发了一个请求,但 Fiddler 记录了两个请求。我认为这可能与接收服务器的重定向有关。

我尝试了三种不同的方法来创建请求。

尝试 1:使用 Restsharp

        public async Task<IActionResult> process()
        {   
            var client = new RestClient("https://host.com");
            var request = new RestRequest("servicename/endpoint", Method.POST);
            request.AddHeader("Accept", "application/json");
            request.AddHeader("Content-Type", "application/json");
            request.AddHeader("Authorization", "Basic SecretToken");

            request.AddParameter("text/json",
                "{\"Key\":\"\",\"Order\":{\"DeliveryDate\":\"5/1/2020\",\"OrderLines\":[{\"ItemNr\":\"12345\",\"Quantity\":1,\"Description\":\"Some string\",\"QuantityPerUnit\":1}],\"Tries\":0}, \"Customernr\":\"123\"}"
                , ParameterType.RequestBody);
            var response = client.Execute(request);
            var content = response.Content;
            return Ok(content);
        }

response 变量在触发此请求时具有 StatusCode Unauthorized。 Fiddler中对应的请求可以看这里:https://imgur.com/lDLLIYH

很明显,根本没有请求标头。不是授权标头,但也没有 Content-Type 标头,例如,即使上面的代码应该设置它。

尝试 2:使用HttpRequestMessage

        public async Task<IActionResult> process2()
        {
            var relativeAddress = "https://host.com/servicename/endpoint";
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, relativeAddress);
            request.Headers.Add("Authorization", "Basic SecretToken");
            // request.Headers.Add("Content-Type", "application/json");
            request.Content = new StringContent(
                "{\"Key\":\"\",\"Order\":{\"DeliveryDate\":\"5/1/2020\",\"OrderLines\":[{\"ItemNr\":\"12345\",\"Quantity\":1,\"Description\":\"Some string\",\"QuantityPerUnit\":1}],\"Tries\":0}, \"Customernr\":\"123\"}"
                Encoding.UTF8,
                "application/json");
            request.Content.Headers.Remove("Content-Type");
            request.Content.Headers.Add("Content-Type", "application/json");
            var response = "";
            await httpClient.SendAsync(request).ContinueWith(responseTask => {
                response = responseTask.Result.Content.ToString();
                Console.WriteLine("Response: {0}", responseTask.Result);
            });
            return Ok();
        }

在这种情况下,响应还显示Unauthorized

Fiddler 中的请求如下所示:https://imgur.com/5asmR0q

尝试 3:使用HttpWebRequest

        public async Task<IActionResult> process3()
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://host.com/servicename/endpoint");
            request.Method = "POST";
            request.AllowAutoRedirect = true;
            request.PreAuthenticate = true;
            request.Headers.Add("Authorization", "Basic SecretToken");
            request.ContentType = "application/json";
            request.Accept = "application/json";

            var response = request.GetResponse();
            var responseStream = response.GetResponseStream();
            if (response == null)
            {
                return null;
            }

            var myStreamReader = new StreamReader(responseStream, Encoding.Default);
            var json = myStreamReader.ReadToEnd();

            responseStream.Close();
            response.Close();
            return Ok();
        }

在这种情况下,响应再次显示未经授权。我什至没有在这个请求中添加正文,但如果我不使用邮递员添加正文,它会抛出 500,因此证明这种方法也不起作用。

Fiddler 中的请求如下所示:https://imgur.com/cOJfwLN

值得注意的是,如果我将AllowAutoRedirect 设置为false,我会收到此错误:

WebException: The remote server returned an error: (307) Temporary Redirect.

我现在不知所措,因为似乎没有为我使用 .NET 发出的任何请求设置任何标头。谁能告诉我我做错了什么或指出我正确的方向?我有一种预感,它与接收服务器的重定向有关。

【问题讨论】:

    标签: c# .net-core http-headers http-post


    【解决方案1】:

    如果您使用的是 ASP.NET Core,那么您应该始终使用与框架更好地集成的 HttpClient

    首先,您需要为您的 OtherWs 创建一个围绕 HttpClient 的包装类。

    例子:

    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace WebApi1
    {
        public class OtherWsClient
        {
            private readonly HttpClient _client;
            public OtherWsClient(HttpClient client)
            {
                _client = client;
            }
    
            public async Task<string> SendRequest()
            {
                var content = new StringContent(
                    "{\"Key\":\"\",\"Order\":{\"DeliveryDate\":\"5/1/2020\",\"OrderLines\":[{\"ItemNr\":\"12345\",\"Quantity\":1,\"Description\":\"Some string\",\"QuantityPerUnit\":1}],\"Tries\":0}, \"Customernr\":\"123\"}",
                    Encoding.UTF8,
                    "application/json");
    
                var response = await _client.PostAsync("/otherwsapi", content);
    
                response.EnsureSuccessStatusCode();
    
                var responseConent = await response.Content.ReadAsStringAsync();
    
                return responseConent;
            }
        }
    }
    
    

    然后你需要在 Startup 类中告诉框架关于新的OtherWs 客户端。

    例子:

            public void ConfigureServices(IServiceCollection services)
            {
                .....
    
                services.AddHttpClient<OtherWsClient>((serviceProvider, client) =>
                {
                    client.BaseAddress = new Uri("base url");
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "secret token");
                });
            }
    

    唯一剩下的就是注入新客户端并在主控制器中使用它。

    例子:

    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApi1.Controllers
    {
        public class MyWsController : ControllerBase
        {
            private readonly OtherWsClient _otherWsClient;
            public MyWsController(OtherWsClient otherWsClient)
            {
                _otherWsClient = otherWsClient;
            }
    
            public async Task<IActionResult> Post()
            {
                var response = await _otherWsClient.SendRequest();
    
                return Content(response);
            }
        }
    }
    
    

    【讨论】:

    • 感谢您的评论,但不幸的是,如果我按照您的建议进行操作,标题仍未设置。我还在启动时添加了这一行:client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));,但仍然没有根据 Fiddler 设置标头,导致以下错误:HttpRequestException:响应状态代码不指示成功:401(未授权)。
    • 可以调试OtherWs源代码还是外部服务?
    • 我们没有设法解决根本问题,但我们通过添加 OtherWs 作为 WCF 引用找到了解决方法。如果我理解正确的话,dotnet 的这个功能使用了肥皂,并且这样做不会受到授权问题的影响。
    猜你喜欢
    • 2021-09-11
    • 2013-08-13
    • 2016-10-25
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    相关资源
    最近更新 更多