go http-proxy
我们这里主要讲使用HTTP/1.1协议中的CONNECT方法建立起来的隧道连接,实现的HTTP Proxy。这种代理的好处就是不用知道客户端请求的数据,只需要原封不动的转发就可以了,对于处理HTTPS的请求就非常方便了,不用解析他的内容,就可以实现代理。
- 启动代理监听
要想做一个HTTP Proxy,我们需要启动一个服务器,监听一个端口,用于接收客户端的请求。Golang给我们提供了强大的net包供我们使用,我们启动一个代理服务器监听非常方便。
l, err := net.Listen("tcp", ":8080") if err != nil {log.Panic(err)}
以上代理我们就实现了一个在8080端口上监听的服务器,我们这里没有写ip地址,默认在所有ip地址上进行监听。如果你只想本机适用,可以使用127.0.0.1:8080,这样机器就访问不了你的代理服务器了。
- 监听接收代理请求
启动了代理服务器,就可以开始接受不了代理请求了,有了请求,我们才能做进一步的处理。
for {client, err := l.Accept() if err != nil {log.Panic(err)} go handleClientRequest(client)}
Listener接口的Accept方法,会接受客户端发来的连接数据,这是一个阻塞型的方法,如果客户端没有连接数据发来,他就是阻塞等待。接收来的连接数据,会马上交给handleClientRequest方法进行处理,这里使用一个go关键字开一个goroutine的目的是不阻塞客户端的接收,代理服务器可以马上接收下一个连接请求。
- 解析请求,获取要访问的IP和端口
有了客户端的代理请求了,我们还得从请求里提取客户端要访问的远程主机的IP和端口,这样我们的代理服务器才可以建立和远程主机的连接,代理转发。
HTTP协议的头信息里就包含有我们需要的主机名(IP)和端口信息,并且是明文的,协议很规范,类似于:
CONNECT www.google.com:443 HTTP/1.1
Host: www.google.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
可以看到我们需要的在第一行,第一个行的信息以空格分开,第一部分CONNECT是请求方法,这里是CONNECT,除此之外还有GET,POST等,都是HTTP协议的标准方法。
第二部分是URL,https的请求只有host和port,http的请求是一个完成的url,等下会看个样例,就明白了。
第三部是HTTP的协议和版本,这个我们不用太关注。
以上是一个https的请求,我们看下http的:
GET http://www.flysnow.org/ HTTP/1.1
Host: www.flysnow.org
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
可以看到htt的,没有端口号(默认是80);比https多了schame—http://。
有了分析,下面我们就可以从HTTP头信息中获取请求的url和method信息了。
var b [1024]byten, err := client.Read(b[:])
if err != nil {log.Println(err) return}
var method, host, address stringfmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)hostPortURL, err := url.Parse(host) if err != nil {log.Println(err) return}
然后需要进一步对url进行解析,获取我们需要的远程服务器信息
if hostPortURL.Opaque == "443" { //https访问address = hostPortURL.Scheme + ":443"} else { //http访问if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端口, 默认80address = hostPortURL.Host + ":80"} else {address = hostPortURL.Host}
这样就完整了获取了要请求服务器的信息,他们可能是以下几种格式
ip:port
hostname:port
domainname:port
就是有可能是ip(v4orv6),有可能是主机名(内网),有可能是域名(dns解析)
- 代理服务器和远程服务器建立连接
有了远程服务器的信息了,就可以进行拨号建立连接了,有了连接,才可以通信。
//获得了请求的host和port,就开始拨号吧
server, err := net.Dial("tcp", address) if err != nil {log.Println(err) return}
数据转发
拨号成功后,就可以进行数据代理传输了
if method == "CONNECT" {fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")} else {server.Write(b[:n])} //进行转发go io.Copy(server, client)io.Copy(client, server)
其中对CONNECT方法有单独的回应,客户端说要建立连接,代理服务器要回应建立好了,然后才可以像HTTP一样请求访问。
完整代码
到这里,我们的代理服务器全部开发完成了,下面是完整的源代码:
package mainimport ( "bytes""fmt""io""log""net""net/url""strings")
func main() {log.SetFlags(log.LstdFlags|log.Lshortfile)l, err := net.Listen("tcp", ":8081") if err != nil {log.Panic(err)} for {client, err := l.Accept() if err != nil {log.Panic(err)} go handleClientRequest(client)}}func handleClientRequest(client net.Conn) { if client == nil { return} defer client.Close() var b [1024]byten, err := client.Read(b[:]) if err != nil {log.Println(err) return} var method, host, address stringfmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)hostPortURL, err := url.Parse(host) if err != nil {log.Println(err) return} if hostPortURL.Opaque == "443" { //https访问address = hostPortURL.Scheme + ":443"} else { //http访问if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端口, 默认80address = hostPortURL.Host + ":80"} else {address = hostPortURL.Host}} //获得了请求的host和port,就开始拨号吧server, err := net.Dial("tcp", address) if err != nil {log.Println(err) return} if method == "CONNECT" {fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")} else {server.Write(b[:n])} //进行转发go io.Copy(server, client)io.Copy(client, server)}
相关文章:
go http-proxy
我们这里主要讲使用HTTP/1.1协议中的CONNECT方法建立起来的隧道连接,实现的HTTP Proxy。这种代理的好处就是不用知道客户端请求的数据,只需要原封不动的转发就可以了,对于处理HTTPS的请求就非常方便了,不用解析他的内容…...
用变压器实现德-英语言翻译【01/8】:嵌入层
一、说明 本文是“用变压器实现德-英语言翻译”系列的第一篇文章。它引入了小规模的嵌入来建立感知系统。接下来是嵌入层的变压器使用。下面简要概述了每种方法,然后是德语到英语的翻译。 二、技术背景 嵌入层的目标是使模型能够详细了解单词、标记或其他输入之间的…...
【vue3.0中ref与reactive的区别及使用】
什么是ref与reactive ref与reactive都是Vue3.0中新增的API,用于响应式数据的处理。 1. ref ref是一个函数,可以用于将一个普通的数据类型转换成响应式数据。ref返回一个包含value属性的对象,通过修改value属性的值,可以触发组件…...
计算机竞赛 基于情感分析的网络舆情热点分析系统
文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…...
C++ 动态分配内存|动态数组
int** arr new int* [n]; for (int i 0; i < n; i) {arr[i] new int[2]; } 以上代码是用C动态分配了一个二维数组arr,其中arr是一个指向int指针的指针,n是一个整数。代码的目的是创建一个包含n个大小为2的整数数组的二维数组。 首先,…...
React Diff算法原理
文章目录 前言Diff算法原理 前言 👉点此(想要了解Diff算法) Diff算法原理 React Diff算法是React用于更新虚拟DOM树的一种算法。它通过比较新旧虚拟DOM树的差异,然后只对有差异的部分进行更新,从而提高性能。 Reac…...
查局域网所有占用IP
查局域网所有占用IP 按:winr 出现下面界面,在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段,下面192.168.20.%i即为你想要ping的网段,%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…...
【MySQL】引擎类型
与其他DBMS一样,MySQL有一个 具体管理和处理数据的内部引擎 。在使用create table语句时,该引擎具体创建表,而在使用select或进行其他数据库处理时,该引擎在内部处理你的请求。多数时候,引擎都隐藏在DBMS内࿰…...
springMVC之HttpMessageConverter
文章目录 前言一、RequestBody二、RequestEntity三、ResponseBody四、SpringMVC处理json五、SpringMVC处理ajax六、RestController注解七、ResponseEntity总结 前言 HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java…...
计算机网络aaaaaaa
差错检测 在一段时间内,传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate) 11111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111…...
pdf.js构建时,报Cannot read property ‘createChildCompiler‘ of undefined #177的解决方法
在本地和CI工具进行构建时,报如下错误。 Cannot read property createChildCompiler of undefined #177解决方法: 找到vue.config.js,在 module.exports {parallel: false, //新增的一行chainWebpack(config) {....config.module.rule(&…...
Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【六】
😀前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【六】,希望你能够喜欢 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章…...
idea配置注释模板
一、类的模板 设置里面依次找到图中标注的地方 填入 /** ${describe} author 填入你的名字 date ${YEAR}-${MONTH}-${DAY} ${TIME} version 1.0.0 */配置完成后,新创建的类就会自动生成类开头的注释 二、方法的注释模板 如图创建模板 步骤6中填入 *** $descrip…...
Unity编辑器扩展:提高效率与创造力的关键
Unity编辑器扩展:提高效率与创造力的关键 前言 一、理解Unity编辑器二、扩展Unity编辑器的意义三、扩展Unity编辑器的必要性四、Unity编辑器的扩展方式五、扩展Unity编辑器的步骤六、Unity编辑器扩展的应用案例七、总结 前言 Unity是一款广泛使用的游戏开发引擎&am…...
Java之对象引用实践
功能概述 从JDK1.2版本开始,程序可以通过4种类型的对象的引用来管控对象的生命周期。这4种引用分别为,强引用、软引用、弱引用和虚引用。本文中针对各种引用做了相关测试,并做对应分析。 功能实践 场景1:弱引用、虚引用、软引用…...
IntelliJ IDEA快捷键大全 + 动图演示!
来自:https://mp.weixin.qq.com/s/434xV02QkDiAFC1yFCAtZw 一、构建/编译 二、文本编辑 三、光标操作 四、文本选择 五、代码折叠 六、多个插入符号和范围选择 七、辅助编码 八、上下文导航 九、查找操作 十、符号导航 十一、代码分析 十二、运行和调试 …...
React 生命周期
React的生命周期 一、什么是React的生命周期二、传统生命周期2.1、挂载(Mounting)2.2、更新(Updating)2.3、卸载(Unmounting)2.4、API2.4.1、render2.4.1.1、Updating 阶段,render调用完还有可能…...
5G智能网关如何解决城市停车痛点难点
2023年上半年,我国汽车新注册登记1175万辆,同比增长5.8%,88个城市汽车保有量超过100万辆,北京、成都等24个城市超过300万辆。随着车辆保有量持续增加,停车难问题长期困扰城市居民,也导致城市路段违停普遍、…...
docker 学习-- 04 实践搭建 1(宝塔)
docker 学习-- 04 实践 1(宝塔) docker 学习-- 01 基础知识 docker 学习-- 02 常用命令 docker 学习-- 03 环境安装 docker 学习-- 04 实践 1(宝塔) docker 学习-- 04 实践 2 (lnpmr环境) 通过上面的学…...
MySQL的mysql-bin.00xx binlog日志文件的清理
目录 引言手工清理配置自动清理 引言 公司一个项目生产环境mysql数据盘占用空间增长得特别快,经过排查发现是开启了mysql的binlog日志。如果把binlog日志关闭,如果操作万一出现问题,就没有办法恢复数据,很不安全,只能…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...
Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集
目录 一、引言:当爬虫遭遇"地域封锁"二、背景解析:分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计:Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...
