golang 反向代理
服务器
package mainimport ("bytes""encoding/base64""encoding/json""fmt""io/ioutil""log""math/rand""net/http""golang.org/x/net/websocket")var cp = make(chan []byte)var res = make(chan []byte, 1)//var uri_chan_map = make(map[string]chan *Return_content)var uri_chan_map = make(map[string]chan map[string]interface{})type Req_Group struct {Method stringHeader http.HeaderBody []byteUri stringHost stringId string}type Return_content struct {Uri string `json:"uri"`Id string `json:"id"`Header http.Header `json:"header"`Body []byte `json:"body"`}func Soket(ws *websocket.Conn) {//设置连接超时, 如果websocket客户端连接后, 客户端响应时间超过设置的等待时间, 则websocket服务端主动断开连接//ws.SetReadDeadline(time.Now().Add(30 * time.Second))//ws.RemoteAddr()远程地址(客户端地址), ws.LocalAddr()本地地址(服务器地址)fmt.Printf("websocket %s->%s 通信连接已建立:\n", ws.RemoteAddr().String(), ws.LocalAddr().String())//标记出错, false表示没出错, true表示出错var err_message = false//外层for循环一次发送一次请求信息for true {data := <-cpws.Write(data)//从缓存中一次只读取1024字节, 如果接收数据过多, 可以将读取内容存在一个可变的数组中,循环读取到缓存无数据即可//将每次读取的1024字节存放在msg中, 然后append到result_msg中msg := make([]byte, 1024)//将所有的读取信息存放在result_msg中var result_msg []byte//内层for循环用来读取response信息for true {n, err := ws.Read(msg)//这里的问题是websocket客户端的问题if err != nil {fmt.Println("websocket客户端出现错误或断开")res_msg := make(map[string]string)res_msg["err"] = err.Error()new_msg, _ := json.Marshal(res_msg)new_msg = []byte(new_msg)result_msg = append(result_msg, new_msg...)//出错就把标记表量设置为trueerr_message = truebreak}if n != 0 && string(msg[:n]) != "OVER" {//msg的元素被打散一个个append进result_msg, 如果不加... 直接写会报错new_msg := msg[:n]result_msg = append(result_msg, new_msg...)//fmt.Printf("读取了%d字节\n", n)msg = make([]byte, 1024)} else if string(msg[:n]) == "OVER" {fmt.Println("websocket传输完毕!")break}}//err_message为true就代表websocket客户端出错, 需要退出发送信息的外循环, 并断开websocket连接if err_message {//将出错信息返回给http客户端res <- result_msg//每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误msg = make([]byte, 1024)result_msg = []byte{}break}res <- result_msg//每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误msg = make([]byte, 1024)result_msg = []byte{}}ws.Close()}func Handler(w http.ResponseWriter, r *http.Request) {//处理请求fmt.Printf("http客户端: %s 请求uri: %s 已连接...\n", r.RemoteAddr, r.URL.Path)//允许访问所有的域w.Header().Set("Access-Control-Allow-Origin", "*")//reflect.TypeOf(r).String(): *http.Requestvar req Req_Groupreq.Method = string(r.Method)req.Header = r.Header//使用随机字符串作为标识req.Id = randomString(10)defer r.Body.Close()body, _ := ioutil.ReadAll(r.Body)req.Body = bodyreq.Uri = r.URL.Pathreq.Host = "https://192.168.18.97"var uri_chan = make(chan map[string]interface{})json_req, _ := json.Marshal(req)//设置随机字符串Id对应的通道uri_chan_map[req.Id] = uri_chancp <- json_reqnew_content := <-uri_chan_map[req.Id]send_message(new_content, w, r)}func send_message(new_content map[string]interface{}, w http.ResponseWriter, r *http.Request) {delete(new_content, "Id")if _, ok := new_content["header"]; ok {//返回response头信息for k, v := range new_content["header"].(map[string]interface{}) {switch tp := v.(type) {case []interface{}:for _, u := range tp {w.Header().Set(k, u.(string))}case string:w.Header().Set(k, v.(string))}}////对body进行base64解码decodeBytes, err := base64.StdEncoding.DecodeString(new_content["body"].(string))if err != nil {log.Fatalln(err)}w.Write(decodeBytes)fmt.Printf("http 客户端: %s: 响应uri: %s 请求的uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string), r.URL.Path)return} else {w.Write([]byte(new_content["err"].(string)))fmt.Printf("出现错误, http 客户端: %s: 请求uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string))return}}//生成随机数函数func randomString(l int) string {var result bytes.Buffervar temp stringfor i := 0; i < l; {temp = string(randInt(65, 90))result.WriteString(temp)i++}return result.String()}func randInt(min int, max int) int {return min + rand.Intn(max-min)}func main() {go func() {for {content := <-resvar new_content map[string]interface{}err := json.Unmarshal(content[:len(content)], &new_content)if err != nil {log.Fatal("err-->Handler json反解析 ", err)}uri_chan_map[new_content["id"].(string)] <- new_content}}()fmt.Println("服务器已开启, 等待客户端连接...")http.HandleFunc("/", Handler)http.Handle("/echo", websocket.Handler(Soket))err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal("err -> main", err)}}
反向代理客户端
package mainimport ("bytes""crypto/tls""encoding/base64""encoding/json""fmt""io""io/ioutil""log""net/http""golang.org/x/net/websocket")type Return_content struct {Uri string `json:"uri"`Id string `json:"id"`Header http.Header `json:"header"`Body []byte `json:"body"`}//客户端地址,自己设置, 但是端口要和服务器监听的端口一致var origin = "http://127.0.0.1:8080/"//服务器地址(在服务器设置端口/后的参数)var url = "ws://127.0.0.1:8080/echo"var ch = make(chan []byte)var res_str = make(chan string)func Forward(ws *websocket.Conn, receive_con map[string]interface{}) {for true {result := <-ch_, err := ws.Write(result)if err != nil {log.Fatal("err -> Forward: ", err)}var over = "OVER"_, err = ws.Write([]byte(over))fmt.Println("转发成功!")start()}}func http_DO(receive_con map[string]interface{}) {//go实现的Client端默认也是要对服务端传过来的数字证书进行校验的,访问https需要让client端略过对证书的校验:tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true},}client := &http.Client{Transport: tr}request_url := "https://192.168.18.97"if _, ok := receive_con["Uri"]; ok {request_url = request_url + receive_con["Uri"].(string)}//根据是否有请求体区分if len(receive_con["Body"].(string)) > 0 {decodeBytes, err := base64.StdEncoding.DecodeString(receive_con["Body"].(string))if err != nil {log.Fatalln(err)}send_message(client, receive_con, request_url, bytes.NewReader(decodeBytes))} else {form_data := bytes.NewReader(nil)send_message(client, receive_con, request_url, form_data)}}func send_message(client *http.Client, receive_con map[string]interface{}, request_url string, form_data io.Reader) {rep, err := http.NewRequest(receive_con["Method"].(string), request_url, form_data)//设置请求头rep.Header.Set("Host", receive_con["Host"].(string))for k1, v1 := range receive_con["Header"].(map[string]interface{}) {if k1 != "Accept-Encoding" && k1 != "Accept-Language" && k1 != "Id" {for _, v2 := range v1.([]interface{}) {rep.Header.Set(k1, v2.(string))}}}resp, err := client.Do(rep)fmt.Println("status: ", resp.StatusCode)if err != nil {fmt.Println("请求出错", err)}Return_response_message(receive_con["Uri"].(string), resp, receive_con["Id"].(string))}func Return_response_message(uri string, resp *http.Response, Id string) {fmt.Println("请求uri: ", uri)defer resp.Body.Close()var return_content Return_contentreturn_content.Id = Idreturn_content.Uri = urireturn_content.Header = resp.Headerbody, err := ioutil.ReadAll(resp.Body)if err != nil {log.Fatal(err)}//将body进行base64编码之后和json.Marshal的body结果一样//encodeString := base64.StdEncoding.EncodeToString(body)//fmt.Println("encodeString: ", encodeString)return_content.Body = bodyjson_return_content, _ := json.Marshal(return_content) // body是base64编码ch <- json_return_content}func start() {ws, err := websocket.Dial(url, "", origin)for true {if err != nil {log.Fatal("err1 -> start: ", err)}var msg = make([]byte, 2048)m, err := ws.Read(msg)if err != nil {log.Fatal("err2 -> start: ", err)}web_message := msg[:m]//解析websocket发送的messagevar jx_web_message map[string]interface{}err = json.Unmarshal(web_message, &jx_web_message)if err != nil {log.Fatal("err3 -> start: ", err)}defer func() {ws.Close()}()go Forward(ws, jx_web_message)http_DO(jx_web_message)}}func main() {start()}
golang 反向代理的更多相关文章
- hasura的golang反向代理
概述 反向代理代码 对请求的处理 对返回值的处理 遇到的问题 概述 一直在寻找一个好用的 graphql 服务, 之前使用比较多的是 prisma, 但是 prisma1 很久不再维护了, 而 pri ...
- golang 实现HTTP代理和反向代理
正向代理 package main import ( "fmt" "io" "net" "net/http" " ...
- golang http proxy反向代理
本文介绍golang中如何进行反向代理. 下面例子中, proxy server接收client 的 http request,转发给true server,并把 true server的返回结果再发 ...
- golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web
golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web Nginx 部署 - beego: 简约 & 强大并存的 Go 应用框架https://bee ...
- IIS 反向代理 golang web开发
一. beego 开发编译 bee run 后会编译成 exe文件 编译生成后发布文件结构为 cmd 运行 cd D:/run beegoDemo.exe run 默认配置端口 不能为 80 跟iis ...
- aProxy: 带认证授权和权限控制的反向代理
前段时间很多数据库因为没有做好权限控制暴露在外网被删然后遭勒索的事件,而类似的有些内网的web服务也会被开放到公网并且没有做任何权限控制的,这样也会有一定的风险.所以就决定写篇文章简单介绍一个小工具. ...
- Nginx插件之openresty反向代理和日志滚动配置案例
Nginx插件之openresty反向代理和日志滚动配置案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.openresty介绍 1>.Nginx介绍 Nginx是一款 ...
- prisma反向代理
概要 为什么要做 prisma 的反向代理 反向代理示例(by golang) prisma 服务 gateway 服务 整体流程 认证 反向代理 权限 总结 概要 接触 prisma 有段时间了, ...
- Nginx-正反向代理及负载均衡
目录 正/反向代理 代理的方式 Nginx代理服务支持的协议 代理实战 部署web01 部署Lb01 Nginx代理常用参数 添加发往后端服务器的请求头信息 代理到后端的TCP连接.响应.返回等超时时 ...
随机推荐
- SAX解析XML文档——(二)
SAX从上向下解析,一行一行解析.节省内存,不适合CRUD. XML文档: <?xml version="1.0" encoding="UTF-8"?&g ...
- UML入门[转]
访问权限控制 class Dummy { - private field1 # protected field2 ~ package method1() + public method2() } Al ...
- 【ARTS】01_11_左耳听风-20190121~20190127
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...
- 【转】inotify+rsync实现实时同步
[转]inotify+rsync实现实时同步 1.1 什么是实时同步:如何实现实时同步 要利用监控服务(inotify),监控同步数据服务器目录中信息的变化 发现目录中数据产生变化,就利用rsync服 ...
- Kaggle Titanic补充篇
1.关于年龄Age 除了利用平均数来填充,还可以利用正态分布得到一些随机数来填充,首先得到已知年龄的平均数mean和方差std,然后生成[ mean-std, mean+std ]之间的随机数,然后 ...
- maven项目有红叉,感叹号如何解决?
红色感叹号,pom.xml文件有红叉 修改了Maven私服服务器的IP地址.可在Maven安装路径下的conf/setting.xml中修改ip地址,具体参照“开发工具”/maven.工程中class ...
- CentOS7 虚拟机设置文件共享 VMWareTools安装遇到的坑
设置文件共享的前提条件是已经安装好VMware Tools. 现在从安装VMware Tools开始讲起: 第一步:安装VMware Tools (如果安装的centos是最小安装,需要提前安装组件g ...
- HTTP SIP 认证
HTTP请求报头: Authorization HTTP响应报头: WWW-Authenticate HTTP认证 基于 质询 /回应( challenge/response)的认证模式. ...
- [学习笔记]Java代码中各种类型变量的内存分配机制
程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据: (1) 寄存器 这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部.然而 ...
- OneNET麒麟座应用开发之六:与气体质量流量控制器通讯
气体质量流量控制器,简称MFC,通常用于在各种检测中,计量气体的流量.在我们的大气环境数据采集站中,要让气流保持稳定,这样才能准确的获取PM25的数据. 我们采用的气体质量流量控制器具备串口通讯功能, ...