curl 工作正常,但 HttpClient PostAsync 不工作
curl is working but HttpClient PostAsync is not
我在 .NET 中复制 cUrl 语句时遇到问题。我正在针对 Oauth API (ORICD SSO) 工作,并且以下 curl 语句运行良好。
curl -i -L -H "Accept: application/json" --data "client_id=APP-XXXXXXXXXXXXXXXX&client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&grant_type=authorization_code&code=VicdvK&redirect_uri=https%3a%2f%2ftst.dev.local%2fsite%2fssocallback.aspx" "https://sandbox.orcid.org/oauth/token"
我从 API 得到我需要的东西。但是,我似乎无法在 C# 中复制这种成功。它一直以 401 Unauthorized 失败。在方法 1 中,我尝试将数据发送为 JSON.
var postdata = new Dictionary<string, string>()
{
{ "client_id", Context.Settings.ClientId },
{ "client_secret", Context.Settings.ClientSecret },
{ "grant_type", Context.Settings.GrantType },
{ "code", Context.HttpContext.Request.Params["code"] },
{ "redirect_uri", Context.Settings.RedirectUri },
};
var jsonContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(postdata), Encoding.UTF8, "application/json");
var response = (new HttpClient())
.PostAsync(Context.Settings.TokenUrl, jsonContent)
.Result;
在方法 2 中,我尝试使用 FormUrlEncodedContent 并通过客户端更改它以设置接受 headers。
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", Context.Settings.ClientId),
new KeyValuePair<string, string>("client_secret", Context.Settings.ClientSecret),
new KeyValuePair<string, string>("grant_type", Context.Settings.GrantType),
new KeyValuePair<string, string>("code", Context.HttpContext.Request.Params["code"]),
new KeyValuePair<string, string>("redirect_uri", Context.Settings.RedirectUri)
});
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var response = client.PostAsync(Context.Settings.TokenUrl, formContent).Result;
当这不起作用时,对于方法 3,我手动构建了数据字符串,使其看起来与 ORCID 页面中的 curl 语句完全一样。我也再次更改了客户端,认为可能有一些默认接受 headers 把事情搞砸了。
var sb = new StringBuilder();
sb.Append("client_id=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.ClientId));
sb.Append("&client_secret=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.ClientSecret));
sb.Append("&grant_type=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.GrantType));
sb.Append("&code=");
sb.Append(HttpUtility.UrlEncode(Context.HttpContext.Request.Params["code"]));
sb.Append("&redirect_uri=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.RedirectUri));
var stringContent = new StringContent(sb.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
using (var request = new HttpRequestMessage(new HttpMethod("POST"), Context.Settings.TokenUrl))
{
request.Content = stringContent;
response = client.SendAsync(request).Result;
}
}
这些方法都失败了。选项 3 失败后,我用上面的 curl 语句进行了测试,它成功了!上面 curl 语句中的数据是直接从 String Builder 值的 Visual Studio 中的直接 window 中提取的,所以我确信它们都使用相同的、正确的凭据。
我不知道还要测试什么。
请注意,我正在使用的网站目前托管在我 运行 curl 语句所在的同一台 Windows 10 笔记本电脑上。
我还尝试使用 Fiddler 观看外出呼叫,但它没有接收到来自我本地 IIS 服务器的 POST 呼叫。它只会显示浏览器重定向,但不会显示代码中的 post。
我明白了。接近方法二:
HttpResponseMessage response;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", Context.Settings.ClientId),
new KeyValuePair<string, string>("client_secret", Context.Settings.ClientSecret),
new KeyValuePair<string, string>("grant_type", Context.Settings.GrantType),
new KeyValuePair<string, string>("code", Context.HttpContext.Request.Params["code"]),
new KeyValuePair<string, string>("redirect_uri", Context.Settings.RedirectUri)
});
response = client.PostAsync(Context.Settings.TokenUrl, formContent).Result;
}
默认情况下,FormUrlEncodedContent
的 header 是 "Content-type", "application/x-www-form-urlencoded"
,这是它需要的。不幸的是,文档没有阐明这一点,我直到现在才明白。
我在 .NET 中复制 cUrl 语句时遇到问题。我正在针对 Oauth API (ORICD SSO) 工作,并且以下 curl 语句运行良好。
curl -i -L -H "Accept: application/json" --data "client_id=APP-XXXXXXXXXXXXXXXX&client_secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&grant_type=authorization_code&code=VicdvK&redirect_uri=https%3a%2f%2ftst.dev.local%2fsite%2fssocallback.aspx" "https://sandbox.orcid.org/oauth/token"
我从 API 得到我需要的东西。但是,我似乎无法在 C# 中复制这种成功。它一直以 401 Unauthorized 失败。在方法 1 中,我尝试将数据发送为 JSON.
var postdata = new Dictionary<string, string>()
{
{ "client_id", Context.Settings.ClientId },
{ "client_secret", Context.Settings.ClientSecret },
{ "grant_type", Context.Settings.GrantType },
{ "code", Context.HttpContext.Request.Params["code"] },
{ "redirect_uri", Context.Settings.RedirectUri },
};
var jsonContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(postdata), Encoding.UTF8, "application/json");
var response = (new HttpClient())
.PostAsync(Context.Settings.TokenUrl, jsonContent)
.Result;
在方法 2 中,我尝试使用 FormUrlEncodedContent 并通过客户端更改它以设置接受 headers。
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", Context.Settings.ClientId),
new KeyValuePair<string, string>("client_secret", Context.Settings.ClientSecret),
new KeyValuePair<string, string>("grant_type", Context.Settings.GrantType),
new KeyValuePair<string, string>("code", Context.HttpContext.Request.Params["code"]),
new KeyValuePair<string, string>("redirect_uri", Context.Settings.RedirectUri)
});
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var response = client.PostAsync(Context.Settings.TokenUrl, formContent).Result;
当这不起作用时,对于方法 3,我手动构建了数据字符串,使其看起来与 ORCID 页面中的 curl 语句完全一样。我也再次更改了客户端,认为可能有一些默认接受 headers 把事情搞砸了。
var sb = new StringBuilder();
sb.Append("client_id=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.ClientId));
sb.Append("&client_secret=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.ClientSecret));
sb.Append("&grant_type=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.GrantType));
sb.Append("&code=");
sb.Append(HttpUtility.UrlEncode(Context.HttpContext.Request.Params["code"]));
sb.Append("&redirect_uri=");
sb.Append(HttpUtility.UrlEncode(Context.Settings.RedirectUri));
var stringContent = new StringContent(sb.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage response;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
using (var request = new HttpRequestMessage(new HttpMethod("POST"), Context.Settings.TokenUrl))
{
request.Content = stringContent;
response = client.SendAsync(request).Result;
}
}
这些方法都失败了。选项 3 失败后,我用上面的 curl 语句进行了测试,它成功了!上面 curl 语句中的数据是直接从 String Builder 值的 Visual Studio 中的直接 window 中提取的,所以我确信它们都使用相同的、正确的凭据。
我不知道还要测试什么。
请注意,我正在使用的网站目前托管在我 运行 curl 语句所在的同一台 Windows 10 笔记本电脑上。
我还尝试使用 Fiddler 观看外出呼叫,但它没有接收到来自我本地 IIS 服务器的 POST 呼叫。它只会显示浏览器重定向,但不会显示代码中的 post。
我明白了。接近方法二:
HttpResponseMessage response;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", Context.Settings.ClientId),
new KeyValuePair<string, string>("client_secret", Context.Settings.ClientSecret),
new KeyValuePair<string, string>("grant_type", Context.Settings.GrantType),
new KeyValuePair<string, string>("code", Context.HttpContext.Request.Params["code"]),
new KeyValuePair<string, string>("redirect_uri", Context.Settings.RedirectUri)
});
response = client.PostAsync(Context.Settings.TokenUrl, formContent).Result;
}
默认情况下,FormUrlEncodedContent
的 header 是 "Content-type", "application/x-www-form-urlencoded"
,这是它需要的。不幸的是,文档没有阐明这一点,我直到现在才明白。