十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
学完了 net/http 和 fasthttp 两个HTTP协议接口的客户端实现,接下来就要开始Server的开发,不学不知道一学吓一跳,居然这两个库还支持Server的开发,太方便了。
成都创新互联是一家集网站建设,桦南企业网站建设,桦南品牌网站建设,网站定制,桦南网站建设报价,网络营销,网络优化,桦南网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
相比于Java的HTTPServer开发基本上都是使用Spring或者Springboot框架,总是要配置各种配置类,各种 handle 对象。Golang的Server开发显得非常简单,就是因为特别简单,或者说没有形成特别统一的规范或者框架,我发现了很多实现方式,HTTP协议基于还是 net/http 和 fasthttp ,但是 handle 语法就多种多样了。
先复习一下: Golang语言HTTP客户端实践 、 Golang fasthttp实践 。
在Golang语言方面,实现某个功能的库可能会比较多,有机会还是要多跟同行交流,指不定就发现了更好用的库。下面我分享我学到的六种Server开发的实现Demo。
基于 net/http 实现,这是一种比较基础的,对于接口和 handle 映射关系处理并不优雅,不推荐使用。
第二种也是基于 net/http ,这种编写语法可以很好地解决第一种的问题,handle和path有了类似配置的语法,可读性提高了很多。
第三个基于 net/http 和 github.com/labstack/echo ,后者主要提供了 Echo 对象用来处理各类配置包括接口和handle映射,功能很丰富,可读性最佳。
第四种依然基于 net/http 实现,引入了 github.com/gin-gonic/gin 的路由,看起来接口和 handle 映射关系比较明晰了。
第五种基于 fasthttp 开发,使用都是 fasthttp 提供的API,可读性尚可,handle配置倒是更像Java了。
第六种依然基于 fasthttp ,用到了 github.com/buaazp/fasthttprouter ,有点奇怪两个居然不在一个GitHub仓库里。使用语法跟第三种方式有点类似,比较有条理,有利于阅读。
golang net/http标准库的client是可以配置各种代理的,http/https/sock5等,不过fasthttp仅支持配置sock5代理,通过定义fasthttp dialfunc实现:
项目中碰到的问题是,ops只提供了用squid搭建的http代理,所以是想重新定义一个http代理的dialfunc,找了fasthttp github仓库的issue,作者提供了一个dialFunc
经测试,访问https的站点是OK的,访问http的站点不行,代理连接不上。先说一下http/https代理的区别,再说原因。
使用代理访问https网站时,会先发CONNECT请求,让代理与目标站点建立一个http tunnel,之后在这个tunnel基础上进行传输,对应到上面的dialFunc过程就是:
可以看到http站点是不需要发CONNECT请求的,而是直接将目标站点的url作为path 填写在http请求头中。
为何上面的dialfunc访问http站点不行呢,查了squid代理的文档,发现squid默认会禁止非https站点通过CONNECT方法建立通道,自己搭了个squid代理去掉配置项,发现上面的dialfunc是可以访问http、https站点的,就是说http,https都先建立通过,再请求。
看了fasthttp的源码,没办法在请求前修改request header中的path为目标站点url,所以如果需要通过fasthttp使用http代理,那么可以使用上面的dialfunc,同时代理需要允许非443端口的站点可以建立通道。如果做不到这一点,那么还是建议使用标准库net/http的client,会更方便一点。
我们在mian函数中,首先初始化配置文件,然后新建http连接。
这个连接创建之后,监听服务器的9999端口。如果url的路径后缀为 "/ws",就转发到ws/ws.go中的IndexHandler方法中。
这个方法中首先我们创建一个websocket的Upgrader实例,然后我们使用Upgrader的upgrade方法来升级一下我们的连接为长连接。
升级完成之后会返回一个*websocket.Conn的连接,我们之后所有的关于连接的操作,都是基于该conn的。
在该连接完成之后,我们将连接存放到一个名为Client的map中,以便之后管理更为方便。
之后,我们启动一个goroutine来读取连接中发送的信息内容,再根据内容进行相应的操作。
网关=反向代理+负载均衡+各种策略,技术实现也有多种多样,有基于 nginx 使用 lua 的实现,比如 openresty、kong;也有基于 zuul 的通用网关;还有就是 golang 的网关,比如 tyk。
这篇文章主要是讲如何基于 golang 实现一个简单的网关。
转自: troy.wang/docs/golang/posts/golang-gateway/
整理:go语言钟文文档:
启动两个后端 web 服务(代码)
这里使用命令行工具进行测试
具体代码
直接使用基础库 httputil 提供的NewSingleHostReverseProxy即可,返回的reverseProxy对象实现了serveHttp方法,因此可以直接作为 handler。
具体代码
director中定义回调函数,入参为*http.Request,决定如何构造向后端的请求,比如 host 是否向后传递,是否进行 url 重写,对于 header 的处理,后端 target 的选择等,都可以在这里完成。
director在这里具体做了:
modifyResponse中定义回调函数,入参为*http.Response,用于修改响应的信息,比如响应的 Body,响应的 Header 等信息。
最终依旧是返回一个ReverseProxy,然后将这个对象作为 handler 传入即可。
参考 2.2 中的NewSingleHostReverseProxy,只需要实现一个类似的、支持多 targets 的方法即可,具体实现见后面。
作为一个网关服务,在上面 2.3 的基础上,需要支持必要的负载均衡策略,比如:
随便 random 一个整数作为索引,然后取对应的地址即可,实现比较简单。
具体代码
使用curIndex进行累加计数,一旦超过 rss 数组的长度,则重置。
具体代码
轮询带权重,如果使用计数递减的方式,如果权重是5,1,1那么后端 rs 依次为a,a,a,a,a,b,c,a,a,a,a…,其中 a 后端会瞬间压力过大;参考 nginx 内部的加权轮询,或者应该称之为平滑加权轮询,思路是:
后端真实节点包含三个权重:
操作步骤:
具体代码
一致性 hash 算法,主要是用于分布式 cache 热点/命中问题;这里用于基于某 key 的 hash 值,路由到固定后端,但是只能是基本满足流量绑定,一旦后端目标节点故障,会自动平移到环上最近的那么个节点。
实现:
具体代码
每一种不同的负载均衡算法,只需要实现添加以及获取的接口即可。
然后使用工厂方法,根据传入的参数,决定使用哪种负载均衡策略。
具体代码
作为网关,中间件必不可少,这类包括请求响应的模式,一般称作洋葱模式,每一层都是中间件,一层层进去,然后一层层出来。
中间件的实现一般有两种,一种是使用数组,然后配合 index 计数;一种是链式调用。
具体代码
这里我介绍两种方法!
一 :用IIS或者Apache之类的web服务器软件实现http文件共享
这里我以IIS为例介绍下用常用的web服务器实现文件共享的方法,具体如下(以我机器为例):
1、打开IIS,打开“网站 -- 默认网站”,右键点击“属性”,点击“主目录”,勾选“目录浏览”选项,如下图所示:
2、进入文件夹C:\Inetpub\wwwroot,拷贝文件“1.7z“到这个目录:
3、打开浏览器,输入本机ip(比如我的:192.168.1.123),即可看到共享的文件并可以下载:
点击“1.7z”即可下载。
二 :用python或者go语言实现http文件共享
1、python实现http文件共享:
用过python的都知道python有一个很牛x的命令:
python -m SimpleHTTPServer
在C:\Python27下运行命令:
打开浏览器,可以看到如下效果:
这个命令的默认端口是8000,如果我再加一个端口参数,可以用其它端口进行访问,命令如下:
打开浏览器:
知道了这个原理,可以写个bat文件,在需要的时候copy到相应的目录双击即可,比如我的httpShare.bat文件如下:
python -m SimpleHTTPServer 80
默认用80端口,访问时候只需要输入我的ip地址即可。
2、go语言实现http文件共享:
上面的方法很方便,windows和linux通吃,不过前提是要安装python
这里我有个用go语言实现的,也是windows和linux通吃(windows下不知道怎么配置的可以参考我之前的文章:,类似C/C++,是代码可移植,使用前你只需编译一次。
下面是示例代码(httpShare.go):
package main
import (
"http"
"fmt"
)
func main(){
h := http.FileServer(http.Dir("."))
var port string
fmt.Printf("Please input port Number: ")
fmt.Scanf("%s",port)
http.ListenAndServe(":"+port, h)
}
运行效果: