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

时间:2021-02-24 19:57:42

标签: c# .net-5

我正在尝试使用 HttpClient without a bodyPostAsync 方法发送 POST 请求。但是,在请求中不断失败并显示 405 Method Not Allowed。显然,该请求是作为 GET 请求而不是 POST 发送的(如下图所示)。

代码示例:

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 发送?

enter image description here


更新

由于这个问题在没有提供任何建设性批评的情况下引起了如此多的仇恨,所以 StackOverflow 做得好,真的做得好。

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

  1. HttpClient 如果响应为 301(重定向),将自动重定向。它不会返回 301 作为状态代码!
  2. 当它进行重定向时,它将请求从 POST 更改为 GET。这是 technically correct,但是,我不知道它会发生。

这两件事结合起来,看起来好像请求是作为 GET 发送的,而实际上,它是一个 POST 请求,带有 301 响应,并自动重定向为 GET。在某些情况下可能很明显,有点遗憾的是,在我的情况下,区别在于 URL 中的一个斜杠。

2 个答案:

答案 0 :(得分:1)

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

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

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

Fiddler showing a POST with a 301 response

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

enter image description here

答案 1 :(得分:0)

在使用集成测试时,当默认启动包含 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);