c# - 难以从 API 接收 HTTP 响应 - 错误请求错误
问题描述
我正在尝试将用户名/密码从应用程序传递到 API 以接收令牌授权密钥。当我尝试这样做时,我收到 400 Bad Request 错误,我不知道为什么。以下是有问题的方法:
public User UserAuthentication(string username, string password)
{
string endpoint = baseURL + "/TOKEN";
// Could be POST maybe
string method = "POST";
Credential jsonObj = new Credential
{
grant_type = "password",
username = username,
password = password
};
string jsonStr = JsonConvert.SerializeObject(jsonObj);
WebClient wc = new WebClient();
//x - www - form - urlencoded
wc.Headers[HttpRequestHeader.ContentType] = "application/x - www - form - urlencoded";
wc.Headers.Add("Access-Control-Allow-Headers", "content-type");
wc.Headers.Add("Access-Control-Allow-Origin", "*");
wc.Headers[HttpRequestHeader.Authorization] = "Bearer <token>";
wc.Headers.Add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS");
string header = wc.Headers.ToString();
try
{
string response = wc.UploadString(endpoint, method, jsonStr);
return JsonConvert.DeserializeObject<User>(response);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
我已经在这个方法中改变了几乎所有的东西来寻找修复。
我做了什么:
- /TOKEN 是 /values & /api/values
- POST 方法是 GET —— 有了这个,我收到“无法发送带有这种动词类型的内容主体”。错误。
- ContentType 更改为“应用程序/json”
- Access-Control-Allow-Origin 有 baseURL
- 检查标题和正文的格式:
标题:
{Content-Type: application/x - www - form - urlencoded
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Origin: *
Authorization: Bearer <token>
Access-Control-Allow-Methods: POST, PUT, GET, DELETE, OPTIONS}
身体:
{"grant_type":"password",
"username":"test@gmail.com",
"password":"password123"}
I obviously have something wrong in my request, I've just run out of ideas to try. I'm not entirely sure if UploadString() is the correct method to be using in this situation, but I couldn't find another method in the WebClient class that would be better. Any help to try and push me in the right direction would be very much appreciated.
解决方案
So what I think you are trying to do is a form-urlencoded post to a "token" endpoint with a username/password grant. These are typically done like so:
using (var request = new HttpRequestMessage(HttpMethod.Post, new Uri("https://example.com/token"))
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "password" },
{ "username", "username@site.com" },
{ "password", "password12345" }
})
})
{
using (var resp = await _client.SendAsync(request))
{
resp.EnsureSuccessStatusCode();
//await resp.Content.ReadAsAsync<BearerToken>();
// for testing purposes, try this:
var returnData = await resp.Content.ReadAsStringAsync();
Console.WriteLine(returnData);
}
}
You should define this outside all scopes where you need to do Http requests:
private static readonly HttpClient _client = new HttpClient();
So, first off, try to stick with HttpClient
. Other patterns such as WebClient
are considered legacy.
Next, CORS headers are typically returned from the server when an OPTIONS call is sent to the server. You aren't doing that here, and you should never have to worry about that kind of stuff inside a C# program running from your computer. So you can drop the access-control header stuff.
Form-urlencoded data is not JSON data. It's a different way to format data. If you want to send JSON data, you should use the content-type application/json
Finally, you are trying to add an Authorization
header. But that doesn't make much sense as you are trying to authenticate yourself to become authorized. If you send the right username/password, you will receive a bearer token that you can use in an Authorization
header for future requests to said service.
Oh and I forgot to add: Whenever you see an error in the [400,499] range (in this case "400 - bad request") it means that you sent something wrong and the server doesn't understand what you are trying to do. For example: a 401 means you sent invalid or missing authorization information. A 400 means your data was probably malformed.
But I like your question... I can see what you were doing and you tried all kinds of different things.
Download a program called Fiddler
if you want to see how HTTP works. It's a great tool to debug your HTTP calls.
推荐阅读
- php - Auth::login() 无法正常工作 laravel 5.7
- java - 为什么我看到枚举常量的字段值确实被序列化/反序列化?在哪种情况下,究竟什么没有在枚举中序列化?
- reactjs - 为什么我的反应函数返回 [object,object]
- mysql - SELECT Where ID in (List of IDs) 并限制MySQL中每个ID的记录
- java - 来自 ArrayList 的 ArrayList 的唯一集合
- java - 我怎么做才能让这个框架中的圆圈实际上自动移动?
- c# - 在这种情况下是否有另一种添加 Console.WriteLine() 的方法
- php - 在窗口 10 中安装 laravel 安装程序时出错
- vue.js - 创建组件并附加到父级的 Vue 指令
- powershell - 如何在 PowerShell 脚本中传递 Windows 凭据?