HTTP Post请求返回400 C#

4
我正在尝试发送一个 HTTP POST 请求以获取 API 令牌。如果成功,它应该返回访问令牌、令牌类型(bearer)和过期时间的字符串值。
我的代码是通用的,我原本期望能够正常运行。但出现了 400 的异常错误“远程服务器返回了错误请求”。我一直在尝试各种方法解决这个问题,但结果并没有改变。
当我调试代码并在 Output 窗口中查看结果时,会出现有关数据流的异常,显示“此流不支持搜索操作”。
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

我的疑惑是它是否由于postData的编码方式而发生。我的客户端密钥类似于:

g/gOvqf5R+FTZZXbwsCbp0WsQjF9B0bl87IBQ8VAJ2Q=

它是否对密钥本身中的字符进行编码,从而构造出错误的请求?我还在POSTMAN上尝试过这个问题,并得到了结果,所以API没有问题。问题仍然在于请求内容。这是一个控制台应用程序。我将我的代码粘贴在下面,并提前感谢您的帮助。
public static APIModel GenerateApiKey()
    {
        var appSettings = ConfigurationManager.AppSettings;

        try
        {
            var urlToCall = string.Format("https://app.example.com/token");
            var uri = new Uri(urlToCall);

            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Method = "POST";

            string postData = "grant_type=client_credentials&client_id=" + appSettings["my_client_id"] + "&client_secret=" + appSettings["my_client_secret"];
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);

            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = byteArray.Length;


            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();

            var response = (HttpWebResponse)request.GetResponse();

            APIModel bearerToken;

            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string jsonFromServer = sr.ReadToEnd();
                bearerToken = JsonConvert.DeserializeObject<APIModel>(jsonFromServer); 
            }

            response.Close();

            return bearerToken;

        }
        catch (Exception e)
        {
            throw new Exception("Error getting a response from API  " + e.Message);
        }

    }

1
你最好使用 HttpClient 而不是 WebRequest。这样更容易与 Web 服务进行交互。 - DavidG
是的,我也考虑过这个。最终我可能会这样做,但我很想知道为什么这种方法失败了。谢谢,DavidG。 - Yavar Hasanov
你在哪一行遇到了错误? - DavidG
var response = (HttpWebResponse)request.GetResponse(); 这就是错误发生的地方。我猜测请求体格式不正确,无法产生响应,因为从语法上看似乎是正确的。 - Yavar Hasanov
你可能需要对客户端密钥进行URL编码,因为它包含某些字符(例如=),尝试这样做。 - DavidG
我刚刚实际上就做到了。所以我的假设是正确的。我必须对id和secret进行编码。所以更新后的postData如下:string postData = "grant_type=client_credentials&client_id=" + HttpUtility.UrlEncode(appSettings["my_client_id"]) + "&client_secret=" + HttpUtility.UrlEncode(appSettings["my_client_secret"]);问题解决了。谢谢。 - Yavar Hasanov
2个回答

2
远程服务器因为收到了错误的数据而给您返回了400错误。您可以尝试获取响应并找出具体的错误,远程服务器有可能会提供更多信息。然而,我发现您的发布数据存在一个问题——客户端秘钥需要进行URL编码。查看其内容,您会发现它以一个“=”符号结尾,这将被解释为一个特殊字符。我还建议更加明确地创建字符串,因此以下代码适用于您:
var postItems = new List<KeyValuePair<string, string>>
{
    new KeyValuePair<string, string>("grant_type", "client_credentials"),
    new KeyValuePair<string, string>("client_id", "client_credentials"),
    new KeyValuePair<string, string>("client_secret", "client_credentials"),
};

string postData = string.Join("&", 
    postItems.Select (kvp => 
        string.Format("{0}={1}", kvp.Key, HttpUtility.UrlEncode(kvp.Value))));

我的修复很快,但这个更整洁。:) 谢谢@DavidG - Yavar Hasanov

0

在组成表单数据时,客户端ID和密钥必须分别进行URL编码。更新后的postData:

string postData = "grant_type=client_credentials&client_id=" + HttpUtility.UrlEncode(appSettings["my_client_id"]) + "&client_secret=" + HttpUtility.UrlEncode(appSettings["my_client_secret"]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接