温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c# - httpclient Displays a negative answer
api asp.net c# httpclient token

c# - httpclient显示否定答案

发布于 2020-04-27 09:53:05

首先,创建令牌的函数。然后,调用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
}}

这种事情的解决办法是什么?

查看更多

提问者
user12724182
被浏览
57
Ignas Z. 2020-02-11 04:18

要完成这项工作,必须了解HTTP请求的两个主要部分:

  • 标头
  • 内容

标头是HTTP请求的第一部分,其中包含有关请求的信息,例如授权,内容长度,内容格式等。

Second part is content. This is your actual data that you want to pass to the server. Content can be formatted in many different ways and your headers are supposed to inform server which type of formatting is used. Two of those formats that are referenced in your snippet are:

  • Form Url/Encoded - this data type is typicaly used with HTML forms. When you have something like

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

this form data is encoded as key1=value1&key2=value2.

  • Json - this is what you want to use for calling PayPal API, it's basically just Json structure appended as content with appropiate headers informing server that it should parse content as Json.

You are having problems because you are conflating headers with content and Form/UrlEncoded and Json content types. FormUrlEncodedContent constructor expects list of form key/value pairs, not headers and when you pass content-type and authorization to it, those key/value pairs are treated as data, not headers. This is where 401 error comes from as server is looking for authorization header not key/value pair in content. Try something like this:

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;
}

First of all, I moved authentication from content to headers. You just need to create a new AuthenticationHeaderValue and pass "Bearer" as scheme (I haven't looked it up, but from your code I assume that API used Bearer authentication scheme).

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

最后,要将Json内容添加到请求中,您应该使用StringContent并传递生成的Json字符串和content-type "application/json"

编辑:测试您的代码,我认为您的最新错误不再是401,而是400-错误的请求,是由无效的内容结构引起的。或者它可能是由无效的令牌解析引起的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;
}