当前位置:首页 > 科技  > 软件

Go语言是 如何实现 HTTP代理 和 反向代理

来源: 责编: 时间:2024-04-26 17:34:32 120观看
导读代理的核心功能可以用一句话概括:接受客户端的请求,转发到后端服务器,获得应答之后返回给客户端。代理的功能有很多,事实上整个互联网到处都充斥着代理服务器。如果所有的 HTTP 访问都是客户端和服务器端直接进行的话,我们

代理的核心功能可以用一句话概括:接受客户端的请求,转发到后端服务器,获得应答之后返回给客户端。aMI28资讯网——每日最新资讯28at.com

代理的功能有很多,事实上整个互联网到处都充斥着代理服务器。如果所有的 HTTP 访问都是客户端和服务器端直接进行的话,我们的网络不仅会变得缓慢,而且性能会大打折扣。aMI28资讯网——每日最新资讯28at.com

代理服务器根据不同的配置和使用,可能会有不同的功能,这些功能主要包括:aMI28资讯网——每日最新资讯28at.com

内容过滤:代理可以根据一定的规则限制某些请求的连接。比如有些公司会设置内部网络无法访问某些购物、游戏网站,或者学校的网络不让学生访问色情暴力的网站等aMI28资讯网——每日最新资讯28at.com

节省成本:代理服务器可以作为缓存使用,对于某些资源只需要第一次访问的时候去下载,以后代理直接把缓存的结果返回给客户端,节约网络带宽的开销。aMI28资讯网——每日最新资讯28at.com

提高性能:通过代理服务器的缓存(比如 CDN)和负载均衡(比如 nginx lb)功能,服务器端可以加速请求的访问,在更快的时间内返回结果)aMI28资讯网——每日最新资讯28at.com

增加安全性:公司可以在内网和外网之间通过代理进行转发,这样不仅对外隐藏了实现的细节,而且可以在代理层对爬虫、病毒性请求进行过滤,保护内部服务aMI28资讯网——每日最新资讯28at.com

所有的这些功能的实现都依赖于代理的特性,它可以在客户端和服务器端做一些事情,根据代理做的事情不同,它的角色和功能也就不同。aMI28资讯网——每日最新资讯28at.com

那么,代理具体可以做哪些事情呢?比如:aMI28资讯网——每日最新资讯28at.com

修改 HTTP 请求:url、header、bodyaMI28资讯网——每日最新资讯28at.com

过滤请求:根据一定的规则丢弃、过滤请求aMI28资讯网——每日最新资讯28at.com

决定转发到哪个后端(可以是静态定义的,也可以是动态决定)aMI28资讯网——每日最新资讯28at.com

保存服务器的应答,后续的请求可以直接使用保存的应答aMI28资讯网——每日最新资讯28at.com

修改应答:对应答做一些格式的转换,修改数据,甚至返回完全不一样的应答数据aMI28资讯网——每日最新资讯28at.com

重试机制,如果后端服务器暂时无法响应,隔一段时间重试aMI28资讯网——每日最新资讯28at.com

正向代理和反向代理

代理可以分为正向代理和反向代理两种。aMI28资讯网——每日最新资讯28at.com

正向代理需要客户端来配置,一般来说我们会通过浏览器或者操作系统提供的工具或者界面来配置。aMI28资讯网——每日最新资讯28at.com

这个时候,代理对客户端不是透明的,客户端需要知道代理的地址并且手动配置。配置了代理,浏览器在发送请求的时候会对报文做特殊的修改。aMI28资讯网——每日最新资讯28at.com

反向代理对客户端是透明的,也就是说客户端一般不知道代理的存在,认为自己是直接和服务器通信。aMI28资讯网——每日最新资讯28at.com

我们大部分访问的网站就是反向代理服务器,反向代理服务器会转发到真正的服务器,一般在反向代理这一层实现负载均衡和高可用的功能。而且这里也可以看到,客户端是不会知道真正服务器端的 ip 地址和端口的,这在一定程度上起到了安全保护的作用。aMI28资讯网——每日最新资讯28at.com

代理服务器怎么知道目的服务器的地址?

在反向代理中,代理服务器要转发的服务器地址都是事先知道的(包括静态配置和动态配置)。比如 使用 nginx 来配置负载均衡 。

而对于正向代理来说,客户端可能访问的服务器地址是无法事先知道的。因为HTTP 协议活动在应用层,它无法获取网络层(IP层)信息,那么该协议要有一个地方可以拿到这个信息。aMI28资讯网——每日最新资讯28at.com

HTTP 中可能保存这个信息的地方有两个:URL 和 header。默认情况下,HTTP 请求的 status line 有三部分组成:方法、uri 和协议版本,比如:aMI28资讯网——每日最新资讯28at.com

GET /index.html HTTP/1.0User-Agent: gohttp 1.0

如果客户端(比如浏览器)知道自己在通过正向代理进行报文传输,那么它会在 status line 加上要访问服务器的真实地址。这个时候发送的报文是:aMI28资讯网——每日最新资讯28at.com

GET http://www.marys-antiques.com/index.html HTTP/1.0User-Agent: gohttp 1.0

代理路径客户端不管是通过代理服务器,还是直接访问后端服务器对于最终的结果是没有区别的,也就是说大多数情况下客户端根本不关心它访问的到底是什么,只需要(准确快速地)拿到想要的信息就够了。aMI28资讯网——每日最新资讯28at.com

但是有时候,我们还是希望知道请求到底在中间经历了哪些代理,比如用来调试网络异常,或者做数据统计,而 HTTP 协议也提供了响应的功能。aMI28资讯网——每日最新资讯28at.com

虽然 RFC 2616 定义了 Via 头部字段来跟踪 HTTP 请求经过的代理路径,但在实际中用的更多的还是 X-Forwarded-For 字段, X-Forwarded-For 是 Squid 缓存代理服务软件引入的,目前已经在规范化在 RFC 7239 文档。aMI28资讯网——每日最新资讯28at.com

X-Forwarded-For 头部格式也比较简单,比如某个服务器接受到请求的对应头部可能是:aMI28资讯网——每日最新资讯28at.com

X-Forwarded-For: client, proxy1, proxy2aMI28资讯网——每日最新资讯28at.com

对应的值有多个字段,每个字段代表中间的一个节点,它们之间由逗号和空格隔开,从左到右距离当前节点越来越近。aMI28资讯网——每日最新资讯28at.com

每个代理服务器会在 X-Forwarded-For 头部填上前一个节点的 ip 地址,这个地址可以通过 TCP 请求的 remote address 获取。为什么每个代理服务器不填写自己的 ip 地址呢?aMI28资讯网——每日最新资讯28at.com

有两个原因,如果由代理服务器填写自己的 ip 地址,那么代理可以很简单地伪造这个地址,而上一个节点的 remote address 是根据 TCP 连接获取的(如果不建立正确的 TCP 连接是无法进行 HTTP 通信的);另外一个原因是如果由当前节点填写 X-Forwarded-For ,那么很多情况客户端无法判断自己是否会通过代理的。aMI28资讯网——每日最新资讯28at.com

NOTE:1、最终客户端或者服务器端接受的请求,X-Forwarded-For 是没有最邻近节点的 ip 地址的,而这个地址可以通过 remote address 获取aMI28资讯网——每日最新资讯28at.com

2、每个节点(不管是客户端、代理服务器、真实服务器)都可以随便更改 X-Forwarded-For 的值,因此这个字段只能作为参考aMI28资讯网——每日最新资讯28at.com

代理服务器实现这个部分我们会介绍如何用 golang 来实现 HTTP 代理服务器,需要读者了解一些 HTTP 服务器端编程的知识。aMI28资讯网——每日最新资讯28at.com

正向代理按照我们之前介绍的代理原理,我们可以编写出这样的代码:aMI28资讯网——每日最新资讯28at.com

package mainimport (    "fmt"    "io"    "net"    "net/http"    "strings")type Pxy struct {}func (p *Pxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {    fmt.Printf("Received request %s %s %s/n", req.Method, req.Host, req.RemoteAddr)    transport :=  http.DefaultTransport    // step 1    outReq := new(http.Request)    *outReq = *req // this only does shallow copies of maps    if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {        if prior, ok := outReq.Header["X-Forwarded-For"]; ok {            clientIP = strings.Join(prior, ", ") + ", " + clientIP        }        outReq.Header.Set("X-Forwarded-For", clientIP)    }    // step 2    res, err := transport.RoundTrip(outReq)    if err != nil {        rw.WriteHeader(http.StatusBadGateway)        return    }    // step 3    for key, value := range res.Header {        for _, v := range value {            rw.Header().Add(key, v)        }    }    rw.WriteHeader(res.StatusCode)    io.Copy(rw, res.Body)    res.Body.Close()}func main() {    fmt.Println("Serve on :8080")    http.Handle("/", &Pxy{})    http.ListenAndServe("0.0.0.0:8080", nil)}

这段代码比较直观,只包含了最核心的代码逻辑,完全按照最上面的代理图例进行组织。一共分成几个步骤:aMI28资讯网——每日最新资讯28at.com

1、代理接收到客户端的请求,复制了原来的请求对象,并根据数据配置新请求的各种参数(添加上 X-Forward-For 头部等)aMI28资讯网——每日最新资讯28at.com

2、把新请求发送到服务器端,并接收到服务器端返回的响应aMI28资讯网——每日最新资讯28at.com

3、代理服务器对响应做一些处理,然后返回给客户端aMI28资讯网——每日最新资讯28at.com

上面的代码运行之后,会在本地的 8080 端口启动代理服务。修改浏览器的代理为 127.0.0.1::8080 再访问网站,可以验证代理正常工作,也能看到它在终端打印出所有的请求信息。aMI28资讯网——每日最新资讯28at.com

虽然这段代码非常简短,但是你可以添加更多的逻辑实现非常有用的功能。比如在请求发送之前进行过滤,根据一定的规则直接阻止某些请求的访问;或者对请求进行限流,某个客户端在一定的时间里执行的请求有最大限额;统计请求的数据进行分析等等。aMI28资讯网——每日最新资讯28at.com

这个代理目前不支持 HTTPS 协议,因为它只提供了 HTTP 请求的转发功能,并没有处理证书和认证有关的内容。aMI28资讯网——每日最新资讯28at.com

如果了解 HTTPS 协议的话,你会明白这种模式下是无法完成 HTTPS 握手的,虽然代理可以和真正的服务器建立连接(知道了对方的公钥和证书),但是代理无法代表服务器和客户端建立连接,因为代理服务器无法知道真正服务器的私钥。aMI28资讯网——每日最新资讯28at.com

反向代理编写反向代理按照上面的思路当然没有问题,只需要在第二步的时候,根据之前的配置修改 outReq 的 URL Host 地址可以了。aMI28资讯网——每日最新资讯28at.com

不过 Golang 已经给我们提供了编写代理的框架:httputil.ReverseProxy 。我们可以用非常简短的代码来实现自己的代理,而且内部的细节问题都已经被很好地处理了。aMI28资讯网——每日最新资讯28at.com

这部分我们会实现一个简单的反向代理,它能够对请求实现负载均衡,随机地把请求发送给某些配置好的后端服务器。使用 httputil.ReverseProxy 编写反向代理最重要的就是实现自己的 Director 对象,这是 GoDoc 对它的介绍:aMI28资讯网——每日最新资讯28at.com

看代码:aMI28资讯网——每日最新资讯28at.com

package mainimport (        "log"        "math/rand"        "net/http"        "net/http/httputil"        "net/url")func NewMultipleHostsReverseProxy(targets []*url.URL) *httputil.ReverseProxy {        director := func(req *http.Request) {                target := targets[rand.Int()%len(targets)]                req.URL.Scheme = target.Scheme                req.URL.Host = target.Host                req.URL.Path = target.Path        }        return &httputil.ReverseProxy{Director: director}}func main() {        proxy := NewMultipleHostsReverseProxy([]*url.URL{                {                        Scheme: "http",                        Host:   "localhost:9091",                },                {                        Scheme: "http",                        Host:   "localhost:9092",                },        })        log.Fatal(http.ListenAndServe(":9090", proxy))}

我们让代理监听在 9090 端口,在后端启动两个返回不同响应的服务器分别监听在 9091 和 9092 端口,通过 curl 访问,可以看到多次请求会返回不同的结果。aMI28资讯网——每日最新资讯28at.com

➜  curl http://127.0.0.1:9090116064a9eb83➜  curl http://127.0.0.1:90908f7ccc11718f

同样的,这段代码也只是一个 demo,存在着很多问题,比如没有错误处理机制,如果后端某个服务器挂了,代理会返回 502 错误,更好的做法是把请求转发到另外的可用服务器。当然也可以添加更多的特性让它更好用,比如动态地添加后端服务器列表;根据后端服务器的负载情况进行负载转发等等。aMI28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-85872-0.htmlGo语言是 如何实现 HTTP代理 和 反向代理

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 从RPC到HTTP:网络通信协议的演变

下一篇: Node.js 重大更新,你知道更新了啥?

标签:
  • 热门焦点
  • Find N3入网:最高支持16+1TB

    Find N3入网:最高支持16+1TB

    OPPO将于近期登场的Find N3折叠屏目前已经正式入网,型号为PHN110。本次Find N3在外观方面相比前两代有很大的变化,不再是小号的横向折叠屏,而是跟别的厂商一样采用了较为常见的
  • 天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    这几年除了手机作为智能生活终端最主要的核心之外,第二个可以成为中心点的产品是什么?——是智能音箱。 手机在执行命令的时候有两种操作方式,手和智能语音助手,而智能音箱只
  • 三言两语说透设计模式的艺术-简单工厂模式

    三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • 一年经验在二线城市面试后端的经验分享

    一年经验在二线城市面试后端的经验分享

    忠告这篇文章只适合2年内工作经验、甚至没有工作经验的朋友阅读。如果你是2年以上工作经验,请果断划走,对你没啥帮助~主人公这篇文章内容来自 「升职加薪」星球星友 的投稿,坐
  • 从 Pulsar Client 的原理到它的监控面板

    从 Pulsar Client 的原理到它的监控面板

    背景前段时间业务团队偶尔会碰到一些 Pulsar 使用的问题,比如消息阻塞不消费了、生产者消息发送缓慢等各种问题。虽然我们有个监控页面可以根据 topic 维度查看他的发送状态,
  • 量化指标是与非:挽救被量化指标扼杀的技术团队

    量化指标是与非:挽救被量化指标扼杀的技术团队

    作者 | 刘新翠整理 | 徐杰承本文整理自快狗打车技术总监刘新翠在WOT2023大会上的主题分享,更多精彩内容及现场PPT,请关注51CTO技术栈公众号,发消息【WOT2023PPT】即可直接领取
  • WebRTC.Net库开发进阶,教你实现屏幕共享和多路复用!

    WebRTC.Net库开发进阶,教你实现屏幕共享和多路复用!

    WebRTC.Net库:让你的应用更亲民友好,实现视频通话无痛接入! 除了基本用法外,还有一些进阶用法可以更好地利用该库。自定义 STUN/TURN 服务器配置WebRTC.Net 默认使用 Google 的
  • 一文搞定Java NIO,以及各种奇葩流

    一文搞定Java NIO,以及各种奇葩流

    大家好,我是哪吒。很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~下次再遇到,
  • 华为和江淮汽车合作开发百万元问界MPV?双方回应来了

    华为和江淮汽车合作开发百万元问界MPV?双方回应来了

    8月1日消息,郭明錤今天在社交平台发文称,华为正在和江淮汽车合作,开发售价在100万元的问界MPV,预计在2024年第2季度量产,销量目标为上市首年交付5万辆。
Top