【问题标题】:httpclient Displays a negative answerhttpclient 显示否定答案
【发布时间】:2020-02-10 05:48:15
【问题描述】:

首先,创建令牌的函数。 然后,调用GetClient(真实令牌)

public static HttpClient GetClient(string token)
{
  HttpClient client = new HttpClient();
  HttpContent content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("ContentType", "application/json"), new KeyValuePair<string, string>("Authorization", "Bearer '" + token + "'") });
  var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
  if (response.IsSuccessStatusCode)
  {
    var responseContent = response.Content;
    string responseString = responseContent.ReadAsStringAsync().Result;
  }
  return client;
}

错误是:

{StatusCode: 401, ReasonPhrase: 'Unauthorized', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{Paypal-Debug-Id: 5341e7ff8a884
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Date: Mon, 10 Feb 2020 05:36:37 GMT
Content-Length: 244
Content-Type: application/json
}}

这样的事情有什么解决办法??

【问题讨论】:

  • 由于您在调用API时获得了未授权,我认为您需要将授权令牌发送为:client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token );
  • 以上方法你试过了吗?
  • 帮助?请!。卡住了

标签: c# asp.net api token httpclient


【解决方案1】:

您必须了解 HTTP 请求的两个主要部分才能使其工作:

  • 标题
  • 内容

Headers 是 HTTP 请求的第一部分,包含有关请求的信息,如授权、内容长度、内容格式等。

第二部分是内容。这是您要传递给服务器的实际数据。内容可以以多种不同的方式格式化,并且您的标题应该通知服务器使用哪种类型的格式化。您的 sn-p 中引用的其中两种格式是:

  • Form Url/Encoded - 此数据类型通常用于 HTML 表单。当你有类似的东西时

<form>
    <input name="key1" value="value1"/>
    <input name="key2" value="value2"/>
</form>

此表单数据编码为key1=value1&amp;key2=value2

  • Json - 这是您要用于调用 PayPal API 的内容,它基本上只是作为内容附加的 Json 结构,并带有适当的标头,通知服务器它应该将内容解析为 Json。

您遇到了问题,因为您将标题与内容以及 Form/UrlEncoded 和 Json 内容类型混为一谈。 FormUrlEncodedContent 构造函数需要表单键/值对列表,而不是标题,当您将内容类型和授权传递给它时,这些键/值对被视为数据,而不是标题。这是 401 错误的来源,因为服务器正在寻找授权标头而不是内容中的键/值对。试试这样的:

public static HttpClient GetClient(string token)
{
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

    var yourContent = new
    {
        key1 = "value1",
        key2 = "value2"
    };
    var jsonContent = JsonConvert.SerializeObject(yourContent);
    var content = new StringContent(jsonContent, Encoding.ASCII, "application/json");

    var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
    if (response.IsSuccessStatusCode)
    {
        var responseContent = response.Content;
        string responseString = responseContent.ReadAsStringAsync().Result;
    }
    return client;
}

首先,我将身份验证从内容移至标题。您只需要创建一个新的AuthenticationHeaderValue 并将"Bearer" 作为方案传递(我没有查过,但从您的代码中我假设API 使用了Bearer 身份验证方案)。

接下来,好像要使用Json content-type。所以你必须生成 Json 作为内容。我使用匿名数据类型执行此操作并将其传递给 JsonConvert(您需要 Newtonsoft.Json 包,如果您复制此代码,Visual Studio 应该会自动建议为您安装该包)。

最后,要向请求添加 Json 内容,您应该使用 StringContent 并传递您生成的 Json 字符串和内容类型 "application/json"

编辑: 测试了您的代码,我假设您的最新错误不再是 401,而是 400 - Bad Request,由无效的内容结构引起。或者它可能是由无效令牌解析引起的 401(可能响应长度有点不同?)。无论哪种方式,都更新了代码以正确地将对象来回转换为 JSON。

public class TokenResponse
{
    [JsonProperty(PropertyName = "scope")]
    public string Scope { get; set; }

    [JsonProperty(PropertyName = "access_token")]
    public string AccessToken { get; set; }

    [JsonProperty(PropertyName = "token_type")]
    public string TokenType { get; set; }

    [JsonProperty(PropertyName = "app_id")]
    public string AppId { get; set; }

    [JsonProperty(PropertyName = "expires_in")]
    public int ExpiresIn { get; set; }

    [JsonProperty(PropertyName = "nonce")]
    public string Nonce { get; set; }
}

public class Amount
{
    [JsonProperty(PropertyName = "currency_code")]
    public string CurrencyCode { get; set; }

    [JsonProperty(PropertyName = "value")]
    public string Value { get; set; }
}

public class PurchaseUnit
{
    [JsonProperty(PropertyName = "amount")]
    public Amount Amount { get; set; }
}

public class OrdersRequest
{
    [JsonProperty(PropertyName = "intent")]
    public string Intent { get; set; }

    [JsonProperty(PropertyName = "purchase_units")]
    public PurchaseUnit[] PurchaseUnits { get; set; }
}

public static void CreateToken()
{
    var client = new HttpClient();
    byte[] authBytes = Encoding.ASCII.GetBytes("user:pass");
    string base64Auth = Convert.ToBase64String(authBytes);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);

    var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("grant_type", "client_credentials") });
    var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v1/oauth2/token"), content).Result;
    if (response.IsSuccessStatusCode)
    {
        var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(response.Content.ReadAsStringAsync().Result);
        GetClient(tokenResponse.AccessToken);
    }
}

public static HttpClient GetClient(string token)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

    var request = new OrdersRequest
    {
        Intent = "CAPTURE",
        PurchaseUnits = new PurchaseUnit[] { new PurchaseUnit
            {
                Amount = new Amount
                {
                    CurrencyCode = "USD",
                    Value = "100.0"
                }
            }
        }
    };

    var jsonContent = JsonConvert.SerializeObject(request);
    var content = new StringContent(jsonContent, Encoding.ASCII, "application/json");

    var response = client.PostAsync(new Uri("https://api.sandbox.paypal.com/v2/checkout/orders"), content).Result;
    if (response.IsSuccessStatusCode)
    {
        var responseString = response.Content.ReadAsStringAsync().Result;
    }
    return client;
}

【讨论】:

  • 首先,非常感谢!!二、根据语法我需要输入TOKEN为JSON格式(drive.google.com/file/d/1OJvr443RhafuEUxWElNtFeqMmhTMw-nB/…
  • 我不确定我是否理解“以 JSON 格式输入 TOKEN”的意思。根据 PayPal documentation 我的代码应该完全符合您的要求,您只需相应地修改 yourContent 即可。该文档说令牌应该作为 Authorization 标头值传递,并且在您的屏幕截图中您也可以这样做。
  • 好的。所以等等,我不明白我在 CONTENT 中放了什么。这不是永久的吗?
  • 我假设说“永久事物”是指持续存在直到 HttpClient 被销毁?如果是这样,那么不是,内容独立于 HttpClient,一旦您调用 PostAsync 就会发送它,仅此而已。另一方面, DefaultRequestHeaders 不是。它们将保留在客户端中(这很好,您希望保留 Authorization 标头)。如果“永久事物”是指它是硬编码的,那么是的。通常,您会创建一个包含请求中的所有字段的类,并用代码中的必需值填充它们。为了简单起见,我在这里使用了匿名数据类型。
  • 查看您的代码,我最好的猜测是 CreateToken 响应长度并不总是相同,并且您的代码无法解析它。或者 GetClient 响应码不是 401 而是 400 无效内容引起的。无论哪种方式,都用工作示例更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2019-08-04
  • 2018-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多