• 基于 Gin 的 HTTP 代理 demo


    上次用 TCP 模拟了一个 HTTP 代理之后,感觉那样还是太简陋了,想着是不是可以用框架来做一个有点实际用处的东西。所以,就思索如何用 golang 的 Gin 框架来实现一个?嗯,对的你没有听错,是 gin 框架。你可能会疑惑,它不是 Web 框架吗,怎么可以用来做代理软件呢?哈哈,其实仔细想一想就明白了。我已经说过了,HTTP 代理的本质其实就是一个 HTTP 服务器!所以,我只要想办法让它来处理所有的路由就行了!

    经过思考之后,我想到了 404 这个东西,通常对于一个 Web 服务来说,它就是不存在的路由。也就是说:
    存在的路由 + 不存在的路由 = 全部的路由
    对于一个 Web 服务,我们是有明确的接口(路由)的,所以会定义很多存在的路由。但是对于一个代理服务器来说,它根本不关心你的路由是什么,也就不需要存在的路由(你根本不知道用户会访问哪些路由),所以我们只需要处理不存在的路由即可。这里不存在的路由是指,不被 Web 服务处理的路由。
    这样描述可能会有些困惑,那么就直说好了,我的想法是:在 Gin 框架中,不定义路由,这样全部的路由都会被认为是不存在的路由了,然后在专门处理 404 的方法中对所有的路由进行处理。相当于通过一个巧妙的方法,从而达到处理所有路由的目的,这样利用它来做一个 HTTP 代理就没有任何问题了。

    代码

    package main
    
    import (
    	"fmt"
    	"io"
    	"log"
    	"net/http"
    	"strings"
    
    	"github.com/gin-gonic/gin"
    )
    
    func main() {
    	r := gin.Default()
    	r.NoRoute(routeProxy)  // 路由代理 handler
    	r.GET("/", routeProxy) // 默认就有一个 / 路由,所以把它也在路由代理中处理
    	r.Run(":8000")         // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
    }
    
    // 这样就可以处理所有的路由情况了
    func routeProxy(c *gin.Context) {
    	// 代理接收到请求将其发出,然后再返回对应的响应。
    	req := c.Request
    	go resolveReq(req) // 看看这个请求干了什么,注意不能代理自己,否则会有问题的
    
    	newReq, _ := http.NewRequest(req.Method, req.URL.String(), req.Body)
    	resp, err := http.DefaultClient.Do(newReq)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer resp.Body.Close()
    
    	data, err := io.ReadAll(resp.Body)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	code := resp.StatusCode
    	c.Status(code) // 响应状态码
    	for k, v := range resp.Header {
    		c.Header(k, strings.Join(v, ","))
    	}
    	c.Header("Server", "CrazyDragonHttpProxy") // 篡改一个响应回复
    	c.Writer.Write(data)                       // 响应数据
    }
    
    func resolveReq(req *http.Request) {
    	fmt.Printf("Method: %s, Host: %s, URL: %s\n", req.Method, req.Host, req.URL.String())
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    注意:这里似乎也不需要这个默认的 /,因为代理的路由和不代理的路由是有区别的。

    代理设置

    请添加图片描述

    这里 http=127.0.0.1,这样就只会代理 http 协议,不会处理 https 协议。因为我这里只是简单的 demo,我也不想去处理 https,那样太麻烦了,我也不是很了解具体怎么做。使用 Fiddler 进行抓包设置时,如果需要抓包 https 就需要安装它的证书,你就知道很麻烦了。

    注意,它现在是一个代理服务器了,所以你不能访问它自己,不然就是代理服务器代理自己了。这里没对这个做处理,所以就会报错。

    请添加图片描述

    测试

    现在想要找一个 http 的网站来测试真的是麻烦了,找了好久才发现一个 http 的网站,毕竟现在还用 http 的网站真的是太稀少了。

    请添加图片描述

    请添加图片描述

    然后就出现问题了,我的电脑风扇开始狂啸,CPU 使用率飙升。然后就是打印上面这些东西了,所以应该就是代理服务器又把请求转发给了自己,然后系统可能就维持了大量的连接导致 CPU 使用率飙升。我开始以为是我的 http.DefaultClient 代码的问题,因为它的默认配置似乎会使用系统的代理。但是我又一想不对呀,因为我并不是在系统之中,我在容器里面呢!我现在把本地开发环境卸载了,所以我是在容器中进行开发的。不过,我又想到虽然我在容器中,但是 docker 还是在系统中的。

    在这里插入图片描述

    所以这个网络请求可能就是下图这样的:红色是用户请求,蓝色是代理的请求,它循环了,然后导致了问题。

    在这里插入图片描述

    所以,我又想了想,解决办法就是还是回到 Windows 本机上运行才行。但是因为本地已经没有了开发环境,所以再另辟蹊径,我只需要在 Windows 上执行就行了,并不需要在 Winwos 上面编译。所以让我们来交叉编译一个 Windows 的版本吧。
    在这里插入图片描述

    不过这玩意在 docker 容器里面呢,我还得拿出去才行,那怎么办才好呢?你听没有听过一个叫 docker cp 的命令!不过根本不需要那么麻烦,因为我这个目录是挂载进来的,我直接去我的挂载目录就行了,哈哈。

    在这里插入图片描述
    请添加图片描述

    演示

    终于是演示成功了,不过我发现它还是会因为无法处理 https 而终止(如果错误了,我就简单终止了程序,当然了你可以不处理直接返回就行了)。https 的那个 connect 方法,这玩意真的和乌云一样,正常的 web 开发用不到它,所以遇到了也就没法处理了(我只知道它是代理服务器建立隧道用的,其它的不清楚)。因为我前面那样设置,我以为是可以跳过 https 协议的,而且我的其它 https 页面是可以正常访问的,不过不知道为什么总有几个还是往代理服务器发送,它处理不了这个东西,导致代理崩溃了。

    请添加图片描述

    请添加图片描述

    PS:
    我刚开始在寻找那个循环请求的问题时,发现了一个老哥写的相似主题的文章。不过,他这个就早多了,好几年前了。不过,我这里最主要的想法是关于 404 的处理,他做的依然是关于指定路由的处理。不过,他使用那个工具直接发送请求还是值得参考的,但是因为这毕竟只是一个玩具,还是不宜过度深入为好,哈哈。

    golang gin 代理和改包

  • 相关阅读:
    .net core添加SQL日志输出
    计算一个日期是一年中的第多天问题(普通、结构体版)
    PHP 实现网页文件上传 及 文件展示
    Linux下内存检测利器Valgrind之Memcheck工具详解
    upstash qStash
    故障注入常用方法有哪些 其重要性是什么
    1488. 避免洪水泛滥
    vue安装element ui失败
    【Plus】三、BaseMapper
    软考高项(已通过,E类人才)-学习笔记材料梳理汇总
  • 原文地址:https://blog.csdn.net/qq_40734247/article/details/134367096