当前位置: 首页 > news >正文

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&#xff0c;其中arr是一个指向int指针的指针&#xff0c;n是一个整数。代码的目的是创建一个包含n个大小为2的整数数组的二维数组。 首先&#xff0c;…...

React Diff算法原理

文章目录 前言Diff算法原理 前言 &#x1f449;点此&#xff08;想要了解Diff算法&#xff09; Diff算法原理 React Diff算法是React用于更新虚拟DOM树的一种算法。它通过比较新旧虚拟DOM树的差异&#xff0c;然后只对有差异的部分进行更新&#xff0c;从而提高性能。 Reac…...

查局域网所有占用IP

查局域网所有占用IP 按&#xff1a;winr 出现下面界面&#xff0c;在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段&#xff0c;下面192.168.20.%i即为你想要ping的网段&#xff0c;%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…...

【MySQL】引擎类型

与其他DBMS一样&#xff0c;MySQL有一个 具体管理和处理数据的内部引擎 。在使用create table语句时&#xff0c;该引擎具体创建表&#xff0c;而在使用select或进行其他数据库处理时&#xff0c;该引擎在内部处理你的请求。多数时候&#xff0c;引擎都隐藏在DBMS内&#xff0…...

springMVC之HttpMessageConverter

文章目录 前言一、RequestBody二、RequestEntity三、ResponseBody四、SpringMVC处理json五、SpringMVC处理ajax六、RestController注解七、ResponseEntity总结 前言 HttpMessageConverter&#xff0c;报文信息转换器&#xff0c;将请求报文转换为Java对象&#xff0c;或将Java…...

计算机网络aaaaaaa

差错检测 在一段时间内&#xff0c;传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate) 11111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111…...

pdf.js构建时,报Cannot read property ‘createChildCompiler‘ of undefined #177的解决方法

在本地和CI工具进行构建时&#xff0c;报如下错误。 Cannot read property createChildCompiler of undefined #177解决方法&#xff1a; 找到vue.config.js&#xff0c;在 module.exports {parallel: false, //新增的一行chainWebpack(config) {....config.module.rule(&…...

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【六】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【六】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…...

idea配置注释模板

一、类的模板 设置里面依次找到图中标注的地方 填入 /** ${describe} author 填入你的名字 date ${YEAR}-${MONTH}-${DAY} ${TIME} version 1.0.0 */配置完成后&#xff0c;新创建的类就会自动生成类开头的注释 二、方法的注释模板 如图创建模板 步骤6中填入 *** $descrip…...

Unity编辑器扩展:提高效率与创造力的关键

Unity编辑器扩展&#xff1a;提高效率与创造力的关键 前言 一、理解Unity编辑器二、扩展Unity编辑器的意义三、扩展Unity编辑器的必要性四、Unity编辑器的扩展方式五、扩展Unity编辑器的步骤六、Unity编辑器扩展的应用案例七、总结 前言 Unity是一款广泛使用的游戏开发引擎&am…...

Java之对象引用实践

功能概述 从JDK1.2版本开始&#xff0c;程序可以通过4种类型的对象的引用来管控对象的生命周期。这4种引用分别为&#xff0c;强引用、软引用、弱引用和虚引用。本文中针对各种引用做了相关测试&#xff0c;并做对应分析。 功能实践 场景1&#xff1a;弱引用、虚引用、软引用…...

IntelliJ IDEA快捷键大全 + 动图演示!

来自&#xff1a;https://mp.weixin.qq.com/s/434xV02QkDiAFC1yFCAtZw 一、构建/编译 二、文本编辑 三、光标操作 四、文本选择 五、代码折叠 六、多个插入符号和范围选择 七、辅助编码 八、上下文导航 九、查找操作 十、符号导航 十一、代码分析 十二、运行和调试 …...

React 生命周期

React的生命周期 一、什么是React的生命周期二、传统生命周期2.1、挂载&#xff08;Mounting&#xff09;2.2、更新&#xff08;Updating&#xff09;2.3、卸载&#xff08;Unmounting&#xff09;2.4、API2.4.1、render2.4.1.1、Updating 阶段&#xff0c;render调用完还有可能…...

5G智能网关如何解决城市停车痛点难点

2023年上半年&#xff0c;我国汽车新注册登记1175万辆&#xff0c;同比增长5.8%&#xff0c;88个城市汽车保有量超过100万辆&#xff0c;北京、成都等24个城市超过300万辆。随着车辆保有量持续增加&#xff0c;停车难问题长期困扰城市居民&#xff0c;也导致城市路段违停普遍、…...

docker 学习-- 04 实践搭建 1(宝塔)

docker 学习-- 04 实践 1&#xff08;宝塔&#xff09; docker 学习-- 01 基础知识 docker 学习-- 02 常用命令 docker 学习-- 03 环境安装 docker 学习-- 04 实践 1&#xff08;宝塔&#xff09; docker 学习-- 04 实践 2 &#xff08;lnpmr环境&#xff09; 通过上面的学…...

MySQL的mysql-bin.00xx binlog日志文件的清理

目录 引言手工清理配置自动清理 引言 公司一个项目生产环境mysql数据盘占用空间增长得特别快&#xff0c;经过排查发现是开启了mysql的binlog日志。如果把binlog日志关闭&#xff0c;如果操作万一出现问题&#xff0c;就没有办法恢复数据&#xff0c;很不安全&#xff0c;只能…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...