You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

.NET Core 3.1中WebClient不跟随307重定向问题咨询

WebClient不跟随307重定向的原因及解决方案

一、为什么AllowAutoRedirect=true仍不处理307?

这其实是.NET框架的默认设计:虽然WebClient底层依赖的HttpWebRequest默认把AllowAutoRedirect设为true,但它不会自动处理307(临时重定向)和308(永久重定向)这两个状态码

原因在于HTTP规范对这两个状态码的要求非常严格——它们强制重定向时必须完全保留原始请求的方法(比如GET/POST)和请求体内容。框架为了避免潜在的安全风险(比如自动重复POST请求可能导致重复提交数据),默认把这两个状态码排除在了自动重定向的处理范围之外,哪怕你显式设置AllowAutoRedirect=true也不会生效。

二、如何实现支持307重定向的文件下载?

这里提供两种方案,你可以根据自己使用的.NET版本选择:

方案1:自定义WebClient(适配.NET Framework老版本)

继承WebClient并重写相关方法,手动捕获307响应并发起新请求,还能添加重定向次数限制避免死循环:

public class RedirectAwareWebClient : WebClient
{
    // 限制最大重定向次数,防止无限循环
    private readonly int _maxRedirects = 5;
    private int _currentRedirectCount = 0;

    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = base.GetWebRequest(address) as HttpWebRequest;
        if (request != null)
        {
            // 关闭框架自动重定向,我们手动处理
            request.AllowAutoRedirect = false;
        }
        return request;
    }

    protected override WebResponse GetWebResponse(WebRequest request)
    {
        var response = base.GetWebResponse(request) as HttpWebResponse;
        if (response != null && 
            (response.StatusCode == HttpStatusCode.TemporaryRedirect || 
             response.StatusCode == (HttpStatusCode)308) && // 部分.NET版本未定义308,直接用数值
             _currentRedirectCount < _maxRedirects)
        {
            _currentRedirectCount++;
            // 获取重定向目标地址
            var redirectUri = new Uri(response.Headers["Location"]);
            // 复制原始请求的方法和头部信息
            var newRequest = (HttpWebRequest)WebRequest.Create(redirectUri);
            newRequest.Method = request.Method;
            foreach (var headerKey in request.Headers.AllKeys)
            {
                newRequest.Headers[headerKey] = request.Headers[headerKey];
            }
            // 递归处理新的请求
            return GetWebResponse(newRequest);
        }
        // 重置计数,方便重复使用该客户端实例
        _currentRedirectCount = 0;
        return response;
    }
}

使用方式和原生WebClient完全一致:

using (var client = new RedirectAwareWebClient())
{
    client.DownloadFile("https://api.spiget.org/v2/resources/10905/download", "your-target-file.zip");
}

方案2:使用HttpClient(推荐,适用于.NET Core/.NET 5+)

HttpClient对307/308的支持更完善,默认就能自动跟随这类重定向(对于GET这种安全请求,框架会自动重复发起请求),代码也更简洁:

// 异步版本(推荐,不阻塞主线程)
using (var httpClient = new HttpClient())
{
    using (var stream = await httpClient.GetStreamAsync("https://api.spiget.org/v2/resources/10905/download"))
    {
        using (var fileStream = new FileStream("your-target-file.zip", FileMode.Create, FileAccess.Write))
        {
            await stream.CopyToAsync(fileStream);
        }
    }
}

// 同步版本(如果业务需要同步执行)
using (var httpClient = new HttpClient())
{
    using (var stream = httpClient.GetStream("https://api.spiget.org/v2/resources/10905/download"))
    {
        using (var fileStream = new FileStream("your-target-file.zip", FileMode.Create, FileAccess.Write))
        {
            stream.CopyTo(fileStream);
        }
    }
}

小提示

  • 如果你使用的是.NET Framework 4.5及以下版本,HttpClient对307的支持有限,优先选择自定义WebClient的方案。
  • 不管用哪种方案,都建议添加重定向次数限制,避免遇到恶意循环重定向导致程序卡死。

内容的提问来源于stack exchange,提问作者Christian Kern

火山引擎 最新活动