为啥 HttpClient.PostAsync 似乎将请求作为 GET 而不是 POST 发送?

Posted

技术标签:

【中文标题】为啥 HttpClient.PostAsync 似乎将请求作为 GET 而不是 POST 发送?【英文标题】:Why does HttpClient.PostAsync appear to be sending the request as a GET rather than POST?为什么 HttpClient.PostAsync 似乎将请求作为 GET 而不是 POST 发送? 【发布时间】:2021-02-24 19:57:42 【问题描述】:

我一直在尝试使用HttpClient without a body 使用PostAsync 方法发送POST 请求。然而,令我完全困惑的是,请求是以GET 而不是POST 的形式发送的。

当然,请求会以405 Method Not Allowed 失败,因为服务器不允许GET

代码示例:

var response = await new HttpClient().PostAsync("https://api.creativecommons.engineering/v1/auth_tokens/token?client_id=adsf&client_secret=asdf&grant_type=client_credentials", null);
Console.WriteLine(response.RequestMessage);

生产:

Method: GET, RequestUri: 'https://api.creativecommons.engineering/v1/auth_tokens/token/?client_id=adsf&client_secret=asdf&grant_type=client_credentials', Version: 1.1

Example in .NET Fiddle

我也尝试过使用 Flurl,但结果相同(我猜它是在后台使用 HttpClient)。

知道为什么PostAsync 将请求作为 GET 而不是 POST 发送吗?


更新

这个问题在没有提供一点建设性的批评的情况下引起了相当多的仇恨......干得好 ***,干得好,非常受欢迎......

如果您遇到类似问题,请注意以下三点:

    HttpClient如果响应为 301(重定向)会自动重定向。它不会将 301 作为状态码返回给您! 在进行重定向时,它将请求从 POST 更改为 GET。这是technically correct,因为为了在重定向服务器时保留方法,需要返回307而不是301。 对照RequestMessage 中的地址检查代码中的地址。这在某些情况下可能很明显,但在我的情况下,重定向涉及添加单个 /,这在调试器窗口中不容易看到!
https://api.creativecommons.engineering/v1/auth_tokens/token?client_id=adsf&client_secret=asdf&grant_type=client_credentials
https://api.creativecommons.engineering/v1/auth_tokens/token/?client_id=adsf&client_secret=asdf&grant_type=client_credentials
                                                            ^    

【问题讨论】:

谢谢大卫。赞成。非常令人困惑的问题,尤其是在集成测试时。我花了很多时间,无法弄清楚为什么我的非常具体的 POST 请求最终会变成 GET。我在下面留下了一些设置步骤用于集成测试设置 【参考方案1】:

我将 null 发布到该正文,看起来它正在抛出 405 并返回一些信息以查看。我相信“GET”的显示是骗人的。

编辑:好的,所以要修改:

首先执行帖子并从服务器接收 301。

随后重定向到另一个端点(作为 GET),结果为 405。因此,您的请求的最终结果表现为带有 405 的 GET。我的错误。

【讨论】:

你需要澄清一下。该代码似乎没有任何“欺骗性”。一个 POST 请求(可能是我的错)似乎是作为 GET 发送的,然后服务器拒绝(返回 405),没有响应(即使有正确的密钥)。 是的,但这不是我要问的……我理解 405 错误。我的问题是为什么 PostAsync 发送的是 GET 请求而不是 POST。为了更清楚,我更改了标题。 因为 301。在路径末尾的单词 token 之后添加一个斜杠,就在 ? 之前开始查询字符串。这将解决您的问题。 非常感谢。可能值得在答案中更清楚地说明 HttpClient 将在 301(重定向)上自动重定向 - 显然,没有任何线索可以追溯到它。我很惊讶其他人以前没有遇到过这个问题。【参考方案2】:

在使用集成测试时,当默认启动包含此内容时,由于 https redirect,您将遇到此问题

var opt = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(opt);
app.UseHttpsRedirection();

仅使用 Microsoft 的 CustomWebApplicationFactory 建议是不够​​的。您必须在 *Fixture 中配置自己的 TestServer,示例如下

            const string baseUrl = "https://localhost:5001";
            const string environmentName = "Test";
            var contentRoot = Environment.CurrentDirectory;

            Configuration = new ConfigurationBuilder()
                .SetBasePath(contentRoot)
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.environmentName.json", true)
                .AddEnvironmentVariables()
                .Build();
            
            var builder = new WebHostBuilder()
                .UseUrls(baseUrl)
                .UseContentRoot(contentRoot)
                .UseEnvironment(environmentName)
                .UseConfiguration(Configuration)
                .UseStartup<TestStartup>();

            Server = new TestServer(builder) BaseAddress = new Uri(baseUrl);

此外,如果您遵循 DDD 并将控制器放在不同的项目中,请确保您的 API 项目包含程序集参考

services.AddControllers(options =>
                    options.Filters.Add(new HttpResponseExceptionFilter()))
                .AddApplicationPart(typeof(Startup).Assembly)
                .AddApplicationPart(typeof(MyController).Assembly);

【讨论】:

以上是关于为啥 HttpClient.PostAsync 似乎将请求作为 GET 而不是 POST 发送?的主要内容,如果未能解决你的问题,请参考以下文章

异步等待 HttpClient.PostAsync 调用

查看 HttpClient.PostAsync 的响应正文

如何使用 HttpClient.PostAsync 发送 XML 内容?

HttpClient.PostAsync 无响应且无异常

HttpClient.PostAsync 的字符编码问题

如何等待PostAsync返回?