.Net HttpClient 使用代理功能

HttpClient 使用代理功能

实际开发中,HttpClient 通过代理访问目标服务器是常见的需求。

本文将全面介绍如何在 .NET 中配置 HttpClient 使用代理(Proxy)功能,包括基础使用方式、代码示例、以及与依赖注入结合的最佳实践。

注意:运行代码之前,先开启Fiddler Classic及其代理功能,充当代理服务器。

初始化

开启Fiddler Classic及其代理功能,充当代理服务器

在这里插入图片描述

导入初始终化笔记文件,并且执行一次

#!import "./Ini.ipynb"//共享变量
var fiddlerProxyAddress = "127.0.0.1:8888";

🧩 什么是代理?

代理(Proxy)是一种中间服务器,用于转发客户端请求到目标服务器。它常用于以下目的:

  • 访问受限资源:企业内网中,通过代理服务器访问外部资源;
  • 提高安全性和隐私保护:代理可隐藏真实 IP 地址,保护目标服务器的隐私和数据安全;
  • 提高性能:代理可使用请求缓存和负载均衡等,减少目标服务器的压力,提高性能;
  • 方便调试、测试
    • 代理服务器可记录请求和响应信息,方便调试和测试;
    • Fiddler Classic等软件,默认是抓不到 HttpClient 的请求的,需要将其设置为代理服务器,才能抓取到 HttpClient 的请求;

在 .NET HttpClient 中,可以通过多种方式来设置代理服务器。

🛠️ 设置 HttpClient 代理

✅ 基本方式使用(无用户名密码)

{   // 设置 SocketsHttpHandler 使用代理var handler = new SocketsHttpHandler(){UseProxy = true,Proxy = new WebProxy(fiddlerProxyAddress),};// 创建 HttpClient,并且请求using (var client = new HttpClient(handler)){var response = await client.GetAsync("https://www.baidu.com");Console.WriteLine($"响应状态:{response.StatusCode}");}
}

执行上面的单元格,应该在fiddler classic 中,抓到请求包:可以查看和管理详细信息.

在这里插入图片描述

✅ 带用户名和密码的代理

{   // 设置 SocketsHttpHandler 使用代理var handler = new SocketsHttpHandler(){UseProxy = true,Proxy = new WebProxy(fiddlerProxyAddress){//正式项目:机密数据一定要脱敏处理或者使用环境变量、机密管理器等手段//因为Fiddler代理服务器,没有用户凭据要求,所以此处随意填写的。需要的话,真实填写正确的用户凭据。Credentials = new NetworkCredential("username", "password"),},};// 创建 HttpClient,并且请求using (var client = new HttpClient(handler)){var response = await client.GetAsync("https://www.baidu.com");Console.WriteLine($"响应状态:{response.StatusCode}");}
}

📦 在IoC和工厂中使用 Proxy [推荐方式]

在 ASP.NET Core 或基于 IServiceCollection 的项目中,可以通过 UseSocketsHttpHandler 扩展方法,统一管理代理服务器配置。

还可以根据客户端的命名不同,进行不同的代理服务器配置!

//IoC或工厂中设置代理
{//IoCvar services = new ServiceCollection();//默认命名客户端services.AddHttpClient<HttpClient>(string.Empty).ConfigureHttpClient(client => {client.BaseAddress = new Uri(webApiBaseUrl);client.Timeout = TimeSpan.FromSeconds(10);})//配置代理服务器.UseSocketsHttpHandler(handlerBuilder =>{handlerBuilder.Configure((handler,s) => {handler.Proxy = new WebProxy(fiddlerProxyAddress);}); });//发送请求var factory = services.BuildServiceProvider().GetRequiredService<IHttpClientFactory>();//正常请求var defaultClient = factory.CreateClient();var defaultContent = await defaultClient.GetStringAsync("api/hello/ping");Console.WriteLine($"正常请求,响应内容为: {defaultContent}");
}

🔄 动态切换代理服务器

要根据请求的不同(请求地址、请求方法、请求头、请求参数等),动态选择使用一同的代理服务器,可以使用Pipeline中间件,来管理。

///<summary>
/// 代理服务选择器中间件
/// 注意:此中间件会短路,必须设置为最后一个中间件
///</summary>
public class ProxySelectorLastHandler : DelegatingHandler
{/// <summary>/// 拦截请求,并动态设置代理/// 注意:会短路其它中间件,要放最后/// </summary>protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken ct){Console.WriteLine("ProxySelectorLastHandler -> SendAsync -> Before");//动态选择示例var proxy = request.RequestUri.Host switch{string url when url.Contains("baidu") => new WebProxy("127.0.0.1:8888"),string url when url.Contains("qq") => new WebProxy("127.0.0.1:8888"),_ => null};InnerHandler = new SocketsHttpHandler{Proxy = proxy,UseProxy = proxy != null};//请求HttpResponseMessage response = await base.SendAsync(request, ct);Console.WriteLine("ProxySelectorLastHandler -> SendAsync -> After");return response;}
}//日志中间件(管道类)
public class LoggerDelegatingHandler : DelegatingHandler
{protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken){Console.WriteLine("LoggerDelegatingHandler -> Send -> Before");HttpResponseMessage response = base.Send(request, cancellationToken);Console.WriteLine("LoggerDelegatingHandler -> Send -> After");return response;}protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){Console.WriteLine("LoggerDelegatingHandler -> SendAsync -> Before");HttpResponseMessage response = await base.SendAsync(request, cancellationToken);Console.WriteLine("LoggerDelegatingHandler -> SendAsync -> After");return response;}
}//使用:ProxySelectorLastHandler必须设置为最后一个中间件
{var handlerLink = new LoggerDelegatingHandler(){InnerHandler = new ProxySelectorLastHandler(),};var myClient = new HttpClient(handlerLink);var response = await myClient.GetAsync("https://www.qq.com");Console.WriteLine(response.StatusCode);Console.WriteLine("---------------------------------------------------");
}// ProxySelectorLastHandler 不是最后一个的话,其它中间件无效(被短路)
{var handlerLink = new ProxySelectorLastHandler(){InnerHandler = new LoggerDelegatingHandler (),};var myClient = new HttpClient(handlerLink);var response = await myClient.GetAsync("https://www.qq.com");Console.WriteLine(response.StatusCode);
}//注意看输出:后面的没有日志中间件的任何输出

🔐 HTTPS 代理信任问题

当使用 HTTPS 代理时,可能会遇到 SSL/TLS 证书不被信任的问题,尤其是在测试环境中使用自签名证书。

✅解决方法一:忽略证书验证(⚠️ 注意:仅用于开发环境)

var handler = new HttpClientHandler
{Proxy = new WebProxy(fiddlerProxyAddress),UseProxy = true,ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};using (var client = new HttpClient(handler))
{ var response = await client.GetAsync("https://www.baidu.com");Console.WriteLine(response.StatusCode);
};

✅ 解决方法二:手动添加根证书信任

using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;var file = Environment.CurrentDirectory + "\\Assets\\FiddlerRoot.cer";
//Console.WriteLine(file);
var rootCert = System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadCertificateFromFile(file);var handler = new HttpClientHandler
{Proxy = new WebProxy(fiddlerProxyAddress),UseProxy = true,ServerCertificateCustomValidationCallback = (request, cert, chain, errors) =>{//return true;return chain.ChainElements.Any(x => x.Certificate.Thumbprint == cert.Thumbprint); // 验证证书链包含指定根证书}
};using (var client = new HttpClient(handler))
{ var response = await client.GetAsync("https://www.baidu.com");Console.WriteLine(response.StatusCode);
};

📌 总结

通过本文,你应该掌握了以下内容:

  • 如何在 HttpClient 中直接设置代理
  • 如何在依赖注入系统中配置全局代理
  • 如何通过环境变量设置代理
  • 如何验证代理是否生效
  • 实际使用中的注意事项
  • 动态选择及证书信任

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/83086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习路线】 游戏客户端开发入门到进阶

目录 游戏客户端开发入门到进阶&#xff1a;系统学习路线与推荐书单一、学习总原则&#xff1a;从底层出发&#xff0c;项目驱动&#xff0c;持续迭代二、推荐学习路线图&#xff08;初学者→进阶&#xff09;第一阶段&#xff1a;语言基础与编程思维第二阶段&#xff1a;游戏开…

精益数据分析(57/126):创业移情阶段的核心要点与实践方法

精益数据分析&#xff08;57/126&#xff09;&#xff1a;创业移情阶段的核心要点与实践方法 在创业的浩瀚征程中&#xff0c;每一个阶段都承载着独特的使命与挑战。今天&#xff0c;我们继续秉持共同进步的理念&#xff0c;深入研读《精益数据分析》&#xff0c;聚焦创业的首…

015枚举之滑动窗口——算法备赛

滑动窗口 最大子数组和 题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 原题链接 思路分析 见代码注解 代码 int maxSubArray(vector<int>& num…

微软系统 红帽系统 网络故障排查:ping、traceroute、netstat

在微软&#xff08;Windows&#xff09;和红帽&#xff08;Red Hat Enterprise Linux&#xff0c;RHEL&#xff09;等系统中&#xff0c;网络故障排查是确保系统正常运行的重要环节。 ping、traceroute&#xff08;在Windows中为tracert&#xff09;和netstat是三个常用的网络…

解构认知边界:论万能方法的本体论批判与方法论重构——基于跨学科视阈的哲学-科学辩证

一、哲学维度的本体论批判 &#xff08;1&#xff09;理性主义的坍缩&#xff1a;从笛卡尔幻想到哥德尔陷阱 笛卡尔在《方法论》中构建的理性主义范式&#xff0c;企图通过"普遍怀疑-数学演绎"双重机制确立绝对方法体系。然而哥德尔不完备定理&#xff08;Gdel, 19…

【网络入侵检测】基于源码分析Suricata的IP分片重组

【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全&#xff0c;欢迎关注与评论。 目录 目录 1.概要 2. 配置信息 2.1 名词介绍 2.2 defrag 配置 3. 代码实现 3.1 配置解析 3.1.1 defrag配置 3.1.2 主机系统策略 3.2 分片重组模块 3.2.1…

二分查找的边界问题

前言 二分查找(Binary Search)是一种高效的查找算法&#xff0c;时间复杂度为O(log n)。它适用于已排序的数组或列表。本文将详细介绍二分查找的两种常见写法&#xff1a;闭区间写法和左闭右开区间写法。 一、二分查找基本思想 二分查找的核心思想是"分而治之"&am…

重庆医科大学附属第二医院外科楼外挡墙自动化监测

1.项目概述 重庆医科大学附属第二医院&#xff0c;重医附二院&#xff0c;是集医疗、教学、科研、预防保健为一体的国家三级甲等综合医院。前身为始建于1892年的“重庆宽仁医院”。医院现有开放床位 1380张&#xff0c;年门诊量超过百万人次&#xff0c;年收治住院病人4.5万人…

【Redis实战篇】秒杀优化

1. 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单…

【idea】调试篇 idea调试技巧合集

前言&#xff1a;之前博主写过一篇idea技巧合集的文章&#xff0c;由于技巧过于多了&#xff0c;文章很庞大&#xff0c;所以特地将调试相关的技巧单独成章, 调试和我们日常开发是息息相关的&#xff0c;用好调试可以事半功倍 文章目录 1. idea调试异步线程2. idea调试stream流…

postman 用法 LTS

postman 用法 LTS File ---- View ---- Show Postman Console

MySQL 数据库故障排查指南

MySQL 数据库故障排查指南 本指南旨在帮助您识别和解决常见的 MySQL 数据库故障。我们将从问题识别开始&#xff0c;逐步深入到具体的故障类型和排查步骤。 1. 问题识别与信息收集 在开始排查之前&#xff0c;首先需要清晰地了解问题的现象和范围。 故障现象&#xff1a; 数…

用AI写简历是否可行?

让AI批量写简历然后投简历是绝对不行的&#xff01;&#xff01;&#xff01; 为什么不行&#xff0c;按照 "招聘经理" 工作经历举例&#xff1a; ai提示词&#xff1a;请帮我写一份招聘经理的工作经历内容&#xff1a; 招聘经理 | XXX科技有限公司 | 2020年…

【从零实现JsonRpc框架#1】Json库介绍

1.JsonCpp第三方库 JSONCPP 是一个开源的 C 库&#xff0c;用于解析和生成 JSON&#xff08;JavaScript Object Notation&#xff09;数据。它提供了简单易用的接口&#xff0c;支持 JSON 的序列化和反序列化操作&#xff0c;适用于处理配置文件、网络通信数据等场景。 2.Jso…

Ubuntu——执行echo $USE什么都不显示

问题&#xff1a;“执行 echo $USER 什么都不显示”&#xff1f; 一、原因分析 环境变量 $USER 未正确设置 $USER 是系统自动定义的环境变量&#xff0c;通常用于表示当前登录的用户名。若该变量未设置或为空&#xff0c;执行 echo $USER 会无输出。可能场景&#xff1a; 用户通…

uni-app学习笔记五--vue3插值表达式的使用

vue3快速上手导航&#xff1a;简介 | Vue.js 模板语法 插值表达式 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span>Message: {{ msg }}</span> 双大括号标签会被替换为相应组件实例中 msg 属性的值。同…

【PSINS工具箱】基于工具箱的单独GNSS导航、单独INS导航、两者结合组合导航,三种导航的对比程序。附完整的代码

本文给出基于PSINS工具箱的单独GNSS导航、单独INS导航、两者结合组合导航(153EKF)的程序。并提供三者的轨迹对比、误差对比。 文章目录 运行结果MATLAB代码代码的简单介绍简介2. 平均绝对误差 (MAE)主要模块运行结果 三轴轨迹图: 各轴误差曲线: 命令行窗口的结果输出: …

C. scanf 函数基础

scanf 函数 1. scanf 函数基础1.1 函数原型与头文件1.2 格式化输入的基本概念2.1 常见格式说明符整数格式说明符浮点数格式说明符字符和字符串格式说明符其他格式说明符2.2 格式说明符的高级用法宽度修饰符精度修饰符跳过输入字段宽度组合修饰符对齐修饰符实际应用示例3.2 精度…

spring cloud loadbalancer实现机房感知的负载均衡

1 概述 在同城多机房情景下&#xff0c;各个机房各自部署一套微服务集群&#xff0c;正常情况下微服务调用在本机房闭环。在如下某些灾难情景&#xff0c;可以尝试拉远调用以最大程度维持业务连续性&#xff0c;这些情景例如&#xff1a; A机房多个服务器宕机。应用由于BUG发…

vue中,created和mounted两个钩子之间调用时差值受什么影响

在 Vue 中&#xff0c;created 和 mounted 是两个生命周期钩子&#xff0c;它们之间的调用时差主要受以下几个因素影响&#xff1a; &#x1f7e2; 1. 模板复杂度与渲染耗时&#xff08;最主要因素&#xff09; mounted 的触发时间是在组件的 DOM 被挂载之后&#xff08;也就是…