如何在C#中发送字符串格式的application/x-www-form-urlencoded请求获取Discord令牌?
解决Discord OAuth2令牌端点的"unsupported_grant_type"错误(C#实现)
问题背景
在JavaScript中通过拼接字符串形式的application/x-www-form-urlencoded请求体,成功从Discord OAuth2令牌端点获取访问令牌,但在C#中使用FormUrlEncodedContent传递参数时,返回{"error": "unsupported_grant_type"}错误——这和之前JS用对象发送请求时的错误完全一致,需要在C#中模拟JS的字符串拼接请求方式。
JavaScript成功代码示例:
var bodyString = `client_id=${clientId}&client_secret=${clientSecret}&grant_type=authorization_code&code=${params['code']}&redirect_uri=https://localhost:4200/callback`; this.http .post('https://discord.com/api/v10/oauth2/token', bodyString, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }) .subscribe((response) => { console.log('response from post', response); });
C#解决方案
直接构造与JavaScript完全一致的字符串请求体,使用StringContent设置正确的Content-Type头发送请求,同时对参数值进行URL编码避免特殊字符破坏格式:
1. 构造编码后的请求体字符串
// 对参数值做URL编码,防止特殊字符导致请求格式错误 var bodyString = $"client_id={Uri.EscapeDataString(_discordSettings.ClientId)}" + $"&client_secret={Uri.EscapeDataString(_discordSettings.ClientSecret)}" + $"&grant_type=authorization_code" + $"&code={Uri.EscapeDataString(code)}" + $"&redirect_uri={Uri.EscapeDataString(redirectUrl)}";
2. 新增处理字符串格式表单的Post方法
public async Task<T?> PostFormUrlEncodedString<T>(string url, string formBodyString) { var client = _httpClientFactory.CreateClient(_httpClients.ToString()); // 构造符合要求的请求内容,指定编码和Content-Type var content = new StringContent(formBodyString, System.Text.Encoding.UTF8, "application/x-www-form-urlencoded"); var apiResponse = await client.PostAsync(url, content); if (!apiResponse.IsSuccessStatusCode) { return default; } return await apiResponse.Content.ReadFromJsonAsync<T>(); }
3. 调用方法获取令牌
var response = await PostFormUrlEncodedString<DiscordAccessTokenResponse>(_discordSettings.TokenAuthEndpoint, bodyString);
说明
使用FormUrlEncodedContent失败的核心原因是,该类在参数编码、请求头细节上和手动拼接字符串存在细微差异,而Discord的OAuth2端点对请求格式的兼容性要求严格。通过完全模拟JavaScript的请求体格式和编码逻辑,就能解决unsupported_grant_type错误。
内容的提问来源于stack exchange,提问作者muttley91
相关产品推荐
相关产品推荐

