【问题标题】:C# HttpClient PostAsync 403 forbidden with SSLC# HttpClient PostAsync 403 禁止使用 SSL
【发布时间】:2020-10-05 16:59:38
【问题描述】:

因为当我进行 POST 时我们切换到具有 SSL 的服务器,所以我总是收到 403 禁止错误,但是如果我使用 WebClient 它工作正常,无论如何我仍然想让它与 HttpClient 一起工作,因为我必须更改很多代码,还有一个调用使用 MultipartFormDataContent 发布文件,而我不能用 WebClient 做到这一点,在 Webclient 中,我可以选择 POST 数据或上传文件,但我需要一次调用 POST 数据和文件.

这里是 HttpClient 和 WebClient 调用的示例

HttpClient(403禁止错误)

 private async void Login_Click(object sender, RoutedEventArgs e)
    {
        Apic = CryptoEngine.DecryptAPI(Apic);
        if (API())
        {
            using (var content = new MultipartFormDataContent())
            {
                if (EmailText.Text.Contains("@") && EmailText.Text.Contains("."))
                {
                    content.Add(new StringContent(EmailText.Text), "\"email\"");
                }
                else
                {
                    content.Add(new StringContent(EmailText.Text), "\"username\"");
                }

                content.Add(new StringContent(PasswordText.Password), "\"password\"");
                using (var httpClient = new HttpClient())
                {
                    httpClient.DefaultRequestHeaders.Clear();
                    httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/json");
                    httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36");
                    httpClient.DefaultRequestHeaders.Add("appName", "CloudMetaPrinter");
                    httpClient.DefaultRequestHeaders.Add("latitude", Apic.Latitude);
                    httpClient.DefaultRequestHeaders.Add("longitude", Apic.Longitude);
                    httpClient.DefaultRequestHeaders.Add("hostname", Apic.IP);
                    httpClient.DefaultRequestHeaders.Add("hostType", "PC");
                    var httpResponse = httpClient.PostAsync(url + "/" + api + "/auth/login", content);
                    responseContent = await httpResponse.Result.Content.ReadAsStringAsync();
                    Result result = JsonConvert.DeserializeObject<Result>(responseContent);

WebClient(工作正常)

private void Login_Click(object sender, RoutedEventArgs e)
    {
        Apic = CryptoEngine.DecryptAPI(Apic);
        if (API())
        {
            string data;
            if (EmailText.Text.Contains("@"))
            {
                data = JsonConvert.SerializeObject(new
                {
                    email = EmailText.Text,
                    password = PasswordText.Password
                });
            }
            else
            {
                data = JsonConvert.SerializeObject(new
                {
                    username = EmailText.Text,
                    password = PasswordText.Password
                });
            }
            using (var httpClient = new WebClient { UseDefaultCredentials = true })
            {
                httpClient.Headers.Add("appName", "CloudMetaPrinter");
                httpClient.Headers.Add("latitude", Apic.Latitude);
                httpClient.Headers.Add("longitude", Apic.Longitude);
                httpClient.Headers.Add("hostname", Apic.IP);
                httpClient.Headers.Add("hostType", "PC");
                httpClient.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
                var httpResponse = httpClient.UploadData(url + "/" + api + "/auth/login", "POST", Encoding.UTF8.GetBytes(data));
                var str = System.Text.Encoding.Default.GetString(httpResponse);
                Result result = JsonConvert.DeserializeObject<Result>(str);

我尝试在标头中进行更改,UseDefaultCredentials = true 等,但没有任何效果。

编辑:我使用 .net core 3.0 Edit2:GetAsync 与 HttpClient 工作正常,问题仅在于 PostAsync。

好的,所以我尝试与 fiddler 进行比较并更改一些内容,以便 httpclient 调用更像 webclient,但我仍然得到 403 左边是 WebClient,右边是 HttpClient Compare image

【问题讨论】:

  • 无论代码如何,您都可以轻松使用fiddler查看发布到服务器时两种方法的不同之处,以帮助您解决未来的问题
  • 您在每种情况下都使用不同的凭据。使用 WebClient,您使用的是 Windows 身份验证。使用 HttpClient,根本不需要身份验证。您甚至没有传递基本身份验证标头。更改 HttpClient 代码以也使用 Windows 身份验证
  • 这两个 sn-ps 也非常不同 - 第一个发布表单,第二个发送 JSON 字符串。为什么您希望它们表现相同?
  • @PanagiotisKanavos 在使用 SSL 服务器之前 HttpClient 起作用了,所以我猜是因为 Windows 身份验证,但我无法找到有关如何更改 HttpClient 以使用 Windows 身份验证的信息
  • @mortb 不,他们最终使用 WebClient,我需要使用 HttpClient。

标签: c# visual-studio


【解决方案1】:

您需要将HttpClienthandler 对象传递给HttpClient 的构造函数。 UseDefaultCredentials 属性已移至 HttpClienthandler

例子:

   using(var handler = new HttpClientHandler())
   {
      handler.UseDefaultCredentials = true;

      using(var client = new HttpClient(handler))
      {

         var response = await client.GetAsync("http://www.contoso.com/");
         response.EnsureSuccessStatusCode();

         var responseBody = await response.Content.ReadAsStringAsync();
   }

(请注意,频繁使用Dispose()HttpClient 可能效率低下,最好重复使用。)

https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netcore-3.1

【讨论】:

  • 我已经尝试过了,但我仍然得到 403 禁止,至少在 post 中,get 我没有设置任何内容,它可以工作
  • 很难比较您问题中的两个示例。您在HttpClient 示例中发布MultipartFormDataContent,在WebClient 示例中发布一个json 字符串,所以他们在做不同的事情。您是否尝试过使用 HttpClient 发布 Json?
  • 我知道这是不同的,但如果我使用没有 SSL 服务器机器人方式的调用,仅使用 SSL,请检查我在提琴手中进行的比较图像,我做了一个很少有变化,所以机器人调用是最有可能的,但我仍然有一些最小的差异,我不知道如何改变它
【解决方案2】:

确保您没有代理阻止呼叫。要么不要使用代理,要么确保您配置了正确的地址和端口。使用 mortb 示例中的处理程序:

using (var handler=new HttpHandler())
{
     handler.UseProxy=false;
     var client=new HttpClient(handler);
     var result=await client.PostAsync(url);
     //… retrieve the content
}

【讨论】:

    【解决方案3】:

    [解决方案] 添加以下标题部分

    Headers.Add("User-Agent: Other");

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-11
      • 2018-11-14
      • 1970-01-01
      • 2020-05-11
      相关资源
      最近更新 更多