如何配置HttpClient在收到301 HTTP状态码时不自动重定向?

68
考虑一个ASP.NET Web API服务,该服务会重定向。
public class ThisController : ApiController
{
    /* more methods */

    public override HttpResponseMessage Post()
    {
        var result = new HttpResponseMessage(HttpStatusCode.MovedPermanently);
        // Post requests should be made to "ThatController" instead.
        string uri = Url.Route("That", null);
        result.Headers.Location = new Uri(uri, UriKind.Relative);
        return result;
    }
}

我将尝试验证将数据POST到“api/this”会重定向到“api/that”,以下是我的测试方法:

[TestMethod]
public void PostRedirects()
{
    using (var client = CreateHttpClient("application/json"))
    {
        var content = CreateContent(expected, "application/json");
        using (var responseMessage = client.PostAsync("api/this", content).Result)
        {
            Assert.AreEqual(HttpStatusCode.MovedPermanently, responseMessage.StatusCode);
            Assert.AreEqual(new Uri("https://api.example.com/api/that"), responseMessage.Headers.Location);
        }
    }
}

protected HttpClient CreateHttpClient(string mediaType)
{
    var client = new HttpClient();
    client.BaseAddress = new Uri("http://api.example.com/");
    MediaTypeWithQualityHeaderValue headerValue = MediaTypeWithQualityHeaderValue.Parse(mediaType);
    client.DefaultRequestHeaders.Accept.Add(headerValue);
    client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("gzip"));
    client.DefaultRequestHeaders.AcceptEncoding.Add(StringWithQualityHeaderValue.Parse("deflate"));
    client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue("MyProduct", "1.0")));
    client.MaxResponseContentBufferSize = 1024*1024*8;
    return client;
}

protected ObjectContent CreateContent(T model, string mediaType)
{
    var requestMessage = new HttpRequestMessage();
    MediaTypeFormatter mediaTypeFormatter = null;
    switch (mediaType)
    {
        case "application/json":
            mediaTypeFormatter = new JsonMediaTypeFormatter();
            break;

        case "application/xml":
        case "text/xml":
            mediaTypeFormatter = new XmlMediaTypeFormatter();
            break;

        default:
            Assert.Fail();
            break;
    }

    return requestMessage.CreateContent(
        model,
        new[] { mediaTypeFormatter },
        new FormatterSelector());
}

实际上,服务器会向客户端发送正确的Location头部和HTTP状态码。然后HttpClient会自动执行GET请求到该URI。因此,我的测试从未通过。

我该如何配置HttpClient以使其在收到301时不自动重定向,以便我可以验证服务器响应?


1
可能是重复的问题:如何让System.Net.Http.HttpClient不跟随302重定向? - Michael Freidgeim
2个回答

129

尝试:

var handler = new HttpClientHandler() 
{
    AllowAutoRedirect = false
};

HttpClient client = new HttpClient(handler);

17
在不需要两个独立的 HttpClient 实例(即允许重定向和不允许重定向的实例)的情况下,是否可以根据每个请求进行操作? - Dai
1
也许你需要这个:handler.MaxAutomaticRedirections = 1 - Konstantin S.
1
@Dai,很遗憾,如果不重新发明轮子是不可能的。但是,如果您不介意使用第三方库,那么这正是我在Flurl 3.0中所做的(https://github.com/tmenier/Flurl/issues/500)。 - Todd Menier
1
将近十年过去了...你如何为使用TestServer.CreateClient()创建的干净环境设置它? - Vergil C.

0
为了澄清这个问题,在客户端的Blazor WASM中,你能做的最好的事情就是阻止重定向发生,这对你的需求可能已经足够了。在这种情况下,你将得到一个状态码为零的响应,没有响应头部、响应内容等等。实际上,无法从重定向响应中获取重定向状态码(301等)、头部等等。
这显然是由于用于实现HttpClientHandler的底层JavaScript API的原因: 如果API依赖于重定向响应,那么在浏览器托管的Blazor WebAssembly中编写API客户端会变得棘手。你可能最终可以通过用户导航操作而不是HttpClient来使其工作,但这样做可能会很麻烦。
希望这能节省一些人的时间。
关于这个主题的一些参考资料: 对于不在浏览器中运行的任何人来说,这是一个非常好的示例:

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