将 RestShapr RestRequest 转换为原生 HttpClient

Convert RestShapr RestRequest to native HttpClient

我有这个 REST 请求;我正在尝试将其转换为 HttpClient。我不想在我的应用程序中使用 RestSharp

我不确定如何在请求中发送空主体:发送响应时我不断收到“错误请求”。

基本上,我调用了一个post方法来登录下面的用户。它在 RestSharp 中有效,但请求需要一个空主体才能成功。

var client = new RestClient(Token.Location + "/users/api/login");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", Token.Value);
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(JsonSerializer.Serialize(new { }));
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

我正在尝试将这段代码转换为在 .net core 3.1 中使用 HttpClient

这是我尝试过的:

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", Token.Value);


var stringContent = new StringContent(string.Empty);
var res = await client.PostAsync(Token.Location + "/users/api/login", stringContent);

var data = await res.Content.ReadAsStringAsync();

我也试过了

...
var content = new StringContent(JsonSerializer.Serialize(new { }), Encoding.UTF8, "application/json");
var res = await client.PostAsync(Token.Location + "/users/api/login", content);
...
var res = await client.PostAsync(Token.Location + "/users/api/login", null);
...
var res = await client.PostAsync(Token.Location + "/users/api/login", "Empty string");

我不断收到“错误请求”,因为我发送的不是空的正文。 我已经在邮递员中尝试过,它适用于 {} 的空原始主体。我在这里错过了什么?

您要做的第一件事是确保您使用的是 shared HttpClient. If you are in ASP.NET Core, use IHttpClientFactory. You can learn why here

既然你要分享你的HttpClient,最好不要使用DefaultReqestHeaders,因为它会影响所有请求,header 字典不是 thread-safe。因此,如果一个线程正在修改 collection,同时另一个线程正在修改,您将崩溃。

这并不是说您应该永远使用DefaultRequestHeaders。如果您不想一遍又一遍地设置相同的 header,它们会很方便。您设置一次该值,所有请求都共享该值。

考虑到这一点,使用 SendAsync 总是好的。此方法采用 HttpRequestMessasage,它允许您将 header 隔离到那个请求。

一个典型的使用场景是:

using (var req = new HttpRequestMessage(HttpMethod.Get,
    new Uri("https://www.example.com")))
{
    req.Headers.Authorization = new AuthenticationHeaderValue("token");
    using (var resp = await _client.SendAsync(req))
    {
        resp.EnsureSuccessStatusCode();
        var data = resp.Content.ReadAsStringAsync();
    }
}

这将向 https://www.example.com 发送 GET 请求,其中 Authorization header 的值为 token.

HttpRequestMessage 有自己的一组 header 与 DefaultRequestHeaders 结合使用。

接下来要考虑的事情,这超出了您的问题范围,但值得提出:尝试使用 UriBuilder 来创建带有片段的 URL。

例如:

var uri = new UriBuilder(Token.Location) { Path = "/users/api/login" }.Uri;

现在您不必担心 Token.Location 是否以 / 结尾。该框架将确保它是 well-formed.

至于将 object 发布为 JSON,这里有一个使用 Newtonsoft.Json 包的示例:

using (var req = new HttpRequestMessage(HttpMethod.Post,
    new Uri("https://www.example.com")))
{
    req.Headers.Authorization = new AuthenticationHeaderValue("token");
    req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    req.Content = new StringContent(
        JsonConvert.SerializeObject(theObjectToSend),
        Encoding.UTF8,
        "application/json");

    using (var resp = await _client.SendAsync(req))
    {
        resp.EnsureSuccessStatusCode();
        var data = JsonConvert.DeserializeObject<object>(
            await resp.Content.ReadAsStringAsync());
    }
}

这将序列化并将适当的 header 应用于您的请求。然后它将读回请求并将其反序列化为 object。您希望将 object 替换为您创建的模型,以便于阅读。

我知道这个答案对于您所问的内容有些言过其实,但我想在人们第一次开始使用 HttpClient 时提供一些提示,因为有一些“陷阱”被遗漏了。

因此,对于您的答案,请使用上面的代码并将 theObjectToSend 替换为 new {},然后看看会发生什么。

如果仍然无法正常工作,请使用 Fiddler 之类的工具来调试您的 HTTP 调用以查看您缺少什么。