You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C# HttpClient获取动态生成CSV文件时遇403禁止访问问题求助

解决C# HttpClient访问动态生成CSV接口返回403 Forbidden的问题

问题分析

你遇到的403 Forbidden错误,本质是服务器识别出你的请求并非来自正规浏览器,因此拦截了非浏览器发起的请求。默认情况下,HttpClient发送的请求不会携带浏览器常用的请求头(比如User-Agent),这是很多网站反爬或基础验证的规则。

解决方案

1. 给HttpClient添加浏览器风格的请求头

最关键的是添加User-Agent模拟浏览器请求;同时补充其他浏览器常用请求头,比如Accept、Accept-Language等,进一步降低被拦截概率。

2. 优化请求逻辑,便于排查问题

直接使用GetStreamAsync会在内部自动调用EnsureSuccessStatusCode抛出异常,不利于排查问题。建议先获取完整响应消息,打印状态码和响应头,方便后续调试。

3. 规范异步代码写法

原代码用Task.Run+Wait处理异步任务容易造成线程阻塞,建议改用async Main和直接await异步方法,符合C#异步编程最佳实践。

修改后的完整代码

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace HttpClientTest
{
    class Program
    {
        private static HttpClient httpClient = new HttpClient();

        // 静态构造函数初始化请求头
        static Program()
        {
            // 模拟Chrome浏览器的User-Agent
            httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36");
            // 指定可接受的内容类型
            httpClient.DefaultRequestHeaders.Accept.ParseAdd("text/csv,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
            // 指定语言偏好
            httpClient.DefaultRequestHeaders.AcceptLanguage.ParseAdd("pl-PL,pl;q=0.8,en-US;q=0.5,en;q=0.3");
        }

        // 改用async Main
        static async Task Main(string[] args)
        {
            await DownloadARiMRData();
        }
 
        private static async Task DownloadARiMRData()
        {
            int startYear = 2020;
            int endYear = DateTime.Now.Year;
            for (int i = 0; i <= (endYear - startYear); i++)
            {
                string yearValue = (startYear + i).ToString();
                string sourceURL = string.Format("https://rejestrupraw.arimr.gov.pl/krpbducsv?search=&rok={0}&woj=&pow=&gmi=&grupa=&uprawa=&pageNumber=1&pageSize=12", yearValue);
                
                string fileName = string.Format(@"Powierzchnie_upraw_w_gminach_{0}.csv", yearValue);
                string targetDirectory = @"D:\Users\ARiMR\";
                try
                {
                    await DownloadAndSave(sourceURL, targetDirectory, fileName);
                    Console.WriteLine($"{yearValue}年数据下载完成");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"下载{yearValue}年数据失败: {ex.Message}");
                }
            }
        }

        private static async Task DownloadAndSave(string sourceFile, string destinationFolder, string destinationFileName)
        {
            Stream fileStream = await GetFileStream(sourceFile);

            if (fileStream != Stream.Null)
            {
                await SaveStream(fileStream, destinationFolder, destinationFileName);
            }
        }

        private static async Task<Stream> GetFileStream(string fileUrl)
        {
            try
            {
                var response = await httpClient.GetAsync(fileUrl);
                // 打印状态码和响应头,方便排查问题
                Console.WriteLine($"请求URL: {fileUrl}");
                Console.WriteLine($"状态码: {response.StatusCode}");
                foreach (var header in response.Headers)
                {
                    Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
                }
                // 确保请求成功,否则抛出异常
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStreamAsync();
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine($"请求错误: {ex.Message}");
                return Stream.Null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"未知错误: {ex.Message}");
                return Stream.Null;
            }
        }

        private static async Task SaveStream(Stream fileStream, string destinationFolder, string destinationFileName)
        {
            if (!Directory.Exists(destinationFolder))
                Directory.CreateDirectory(destinationFolder);

            string path = Path.Combine(destinationFolder, destinationFileName);

            using (FileStream outputFileStream = new FileStream(path, FileMode.Create))
            {
                await fileStream.CopyToAsync(outputFileStream);
            }
        }
    }
}

额外调试建议

如果修改后仍然返回403,可以打开浏览器开发者工具(F12),切换到网络标签页,手动下载一次CSV,查看请求的所有头信息(比如Referer、Cookie等),然后将这些头全部添加到httpClient.DefaultRequestHeaders中,完全模拟浏览器的请求行为。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 22:00:17