服务器

  1. package main
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "io/ioutil"
  8. "log"
  9. "math/rand"
  10. "net/http"
  11. "golang.org/x/net/websocket"
  12. )
  13. var cp = make(chan []byte)
  14. var res = make(chan []byte, 1)
  15. //var uri_chan_map = make(map[string]chan *Return_content)
  16. var uri_chan_map = make(map[string]chan map[string]interface{})
  17. type Req_Group struct {
  18. Method string
  19. Header http.Header
  20. Body []byte
  21. Uri string
  22. Host string
  23. Id string
  24. }
  25. type Return_content struct {
  26. Uri string `json:"uri"`
  27. Id string `json:"id"`
  28. Header http.Header `json:"header"`
  29. Body []byte `json:"body"`
  30. }
  31. func Soket(ws *websocket.Conn) {
  32. //设置连接超时, 如果websocket客户端连接后, 客户端响应时间超过设置的等待时间, 则websocket服务端主动断开连接
  33. //ws.SetReadDeadline(time.Now().Add(30 * time.Second))
  34. //ws.RemoteAddr()远程地址(客户端地址), ws.LocalAddr()本地地址(服务器地址)
  35. fmt.Printf("websocket %s->%s 通信连接已建立:\n", ws.RemoteAddr().String(), ws.LocalAddr().String())
  36. //标记出错, false表示没出错, true表示出错
  37. var err_message = false
  38. //外层for循环一次发送一次请求信息
  39. for true {
  40. data := <-cp
  41. ws.Write(data)
  42. //从缓存中一次只读取1024字节, 如果接收数据过多, 可以将读取内容存在一个可变的数组中,循环读取到缓存无数据即可
  43. //将每次读取的1024字节存放在msg中, 然后append到result_msg中
  44. msg := make([]byte, 1024)
  45. //将所有的读取信息存放在result_msg中
  46. var result_msg []byte
  47. //内层for循环用来读取response信息
  48. for true {
  49. n, err := ws.Read(msg)
  50. //这里的问题是websocket客户端的问题
  51. if err != nil {
  52. fmt.Println("websocket客户端出现错误或断开")
  53. res_msg := make(map[string]string)
  54. res_msg["err"] = err.Error()
  55. new_msg, _ := json.Marshal(res_msg)
  56. new_msg = []byte(new_msg)
  57. result_msg = append(result_msg, new_msg...)
  58. //出错就把标记表量设置为true
  59. err_message = true
  60. break
  61. }
  62. if n != 0 && string(msg[:n]) != "OVER" {
  63. //msg的元素被打散一个个append进result_msg, 如果不加... 直接写会报错
  64. new_msg := msg[:n]
  65. result_msg = append(result_msg, new_msg...)
  66. //fmt.Printf("读取了%d字节\n", n)
  67. msg = make([]byte, 1024)
  68. } else if string(msg[:n]) == "OVER" {
  69. fmt.Println("websocket传输完毕!")
  70. break
  71. }
  72. }
  73. //err_message为true就代表websocket客户端出错, 需要退出发送信息的外循环, 并断开websocket连接
  74. if err_message {
  75. //将出错信息返回给http客户端
  76. res <- result_msg
  77. //每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误
  78. msg = make([]byte, 1024)
  79. result_msg = []byte{}
  80. break
  81. }
  82. res <- result_msg
  83. //每次把response信息返回给客户端之后, 要将msg, result_msg清空, 否则会出之前的信息和现在的信息黏连的错误
  84. msg = make([]byte, 1024)
  85. result_msg = []byte{}
  86. }
  87. ws.Close()
  88. }
  89. func Handler(w http.ResponseWriter, r *http.Request) {
  90. //处理请求
  91. fmt.Printf("http客户端: %s 请求uri: %s 已连接...\n", r.RemoteAddr, r.URL.Path)
  92. //允许访问所有的域
  93. w.Header().Set("Access-Control-Allow-Origin", "*")
  94. //reflect.TypeOf(r).String(): *http.Request
  95. var req Req_Group
  96. req.Method = string(r.Method)
  97. req.Header = r.Header
  98. //使用随机字符串作为标识
  99. req.Id = randomString(10)
  100. defer r.Body.Close()
  101. body, _ := ioutil.ReadAll(r.Body)
  102. req.Body = body
  103. req.Uri = r.URL.Path
  104. req.Host = "https://192.168.18.97"
  105. var uri_chan = make(chan map[string]interface{})
  106. json_req, _ := json.Marshal(req)
  107. //设置随机字符串Id对应的通道
  108. uri_chan_map[req.Id] = uri_chan
  109. cp <- json_req
  110. new_content := <-uri_chan_map[req.Id]
  111. send_message(new_content, w, r)
  112. }
  113. func send_message(new_content map[string]interface{}, w http.ResponseWriter, r *http.Request) {
  114. delete(new_content, "Id")
  115. if _, ok := new_content["header"]; ok {
  116. //返回response头信息
  117. for k, v := range new_content["header"].(map[string]interface{}) {
  118. switch tp := v.(type) {
  119. case []interface{}:
  120. for _, u := range tp {
  121. w.Header().Set(k, u.(string))
  122. }
  123. case string:
  124. w.Header().Set(k, v.(string))
  125. }
  126. }
  127. ////对body进行base64解码
  128. decodeBytes, err := base64.StdEncoding.DecodeString(new_content["body"].(string))
  129. if err != nil {
  130. log.Fatalln(err)
  131. }
  132. w.Write(decodeBytes)
  133. fmt.Printf("http 客户端: %s: 响应uri: %s 请求的uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string), r.URL.Path)
  134. return
  135. } else {
  136. w.Write([]byte(new_content["err"].(string)))
  137. fmt.Printf("出现错误, http 客户端: %s: 请求uri: %s 已完成\n", r.RemoteAddr, new_content["uri"].(string))
  138. return
  139. }
  140. }
  141. //生成随机数函数
  142. func randomString(l int) string {
  143. var result bytes.Buffer
  144. var temp string
  145. for i := 0; i < l; {
  146. temp = string(randInt(65, 90))
  147. result.WriteString(temp)
  148. i++
  149. }
  150. return result.String()
  151. }
  152. func randInt(min int, max int) int {
  153. return min + rand.Intn(max-min)
  154. }
  155. func main() {
  156. go func() {
  157. for {
  158. content := <-res
  159. var new_content map[string]interface{}
  160. err := json.Unmarshal(content[:len(content)], &new_content)
  161. if err != nil {
  162. log.Fatal("err-->Handler json反解析 ", err)
  163. }
  164. uri_chan_map[new_content["id"].(string)] <- new_content
  165. }
  166. }()
  167. fmt.Println("服务器已开启, 等待客户端连接...")
  168. http.HandleFunc("/", Handler)
  169. http.Handle("/echo", websocket.Handler(Soket))
  170. err := http.ListenAndServe(":8080", nil)
  171. if err != nil {
  172. log.Fatal("err -> main", err)
  173. }
  174. }

反向代理客户端

  1. package main
  2. import (
  3. "bytes"
  4. "crypto/tls"
  5. "encoding/base64"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "log"
  11. "net/http"
  12. "golang.org/x/net/websocket"
  13. )
  14. type Return_content struct {
  15. Uri string `json:"uri"`
  16. Id string `json:"id"`
  17. Header http.Header `json:"header"`
  18. Body []byte `json:"body"`
  19. }
  20. //客户端地址,自己设置, 但是端口要和服务器监听的端口一致
  21. var origin = "http://127.0.0.1:8080/"
  22. //服务器地址(在服务器设置端口/后的参数)
  23. var url = "ws://127.0.0.1:8080/echo"
  24. var ch = make(chan []byte)
  25. var res_str = make(chan string)
  26. func Forward(ws *websocket.Conn, receive_con map[string]interface{}) {
  27. for true {
  28. result := <-ch
  29. _, err := ws.Write(result)
  30. if err != nil {
  31. log.Fatal("err -> Forward: ", err)
  32. }
  33. var over = "OVER"
  34. _, err = ws.Write([]byte(over))
  35. fmt.Println("转发成功!")
  36. start()
  37. }
  38. }
  39. func http_DO(receive_con map[string]interface{}) {
  40. //go实现的Client端默认也是要对服务端传过来的数字证书进行校验的,访问https需要让client端略过对证书的校验:
  41. tr := &http.Transport{
  42. TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  43. }
  44. client := &http.Client{Transport: tr}
  45. request_url := "https://192.168.18.97"
  46. if _, ok := receive_con["Uri"]; ok {
  47. request_url = request_url + receive_con["Uri"].(string)
  48. }
  49. //根据是否有请求体区分
  50. if len(receive_con["Body"].(string)) > 0 {
  51. decodeBytes, err := base64.StdEncoding.DecodeString(receive_con["Body"].(string))
  52. if err != nil {
  53. log.Fatalln(err)
  54. }
  55. send_message(client, receive_con, request_url, bytes.NewReader(decodeBytes))
  56. } else {
  57. form_data := bytes.NewReader(nil)
  58. send_message(client, receive_con, request_url, form_data)
  59. }
  60. }
  61. func send_message(client *http.Client, receive_con map[string]interface{}, request_url string, form_data io.Reader) {
  62. rep, err := http.NewRequest(receive_con["Method"].(string), request_url, form_data)
  63. //设置请求头
  64. rep.Header.Set("Host", receive_con["Host"].(string))
  65. for k1, v1 := range receive_con["Header"].(map[string]interface{}) {
  66. if k1 != "Accept-Encoding" && k1 != "Accept-Language" && k1 != "Id" {
  67. for _, v2 := range v1.([]interface{}) {
  68. rep.Header.Set(k1, v2.(string))
  69. }
  70. }
  71. }
  72. resp, err := client.Do(rep)
  73. fmt.Println("status: ", resp.StatusCode)
  74. if err != nil {
  75. fmt.Println("请求出错", err)
  76. }
  77. Return_response_message(receive_con["Uri"].(string), resp, receive_con["Id"].(string))
  78. }
  79. func Return_response_message(uri string, resp *http.Response, Id string) {
  80. fmt.Println("请求uri: ", uri)
  81. defer resp.Body.Close()
  82. var return_content Return_content
  83. return_content.Id = Id
  84. return_content.Uri = uri
  85. return_content.Header = resp.Header
  86. body, err := ioutil.ReadAll(resp.Body)
  87. if err != nil {
  88. log.Fatal(err)
  89. }
  90. //将body进行base64编码之后和json.Marshal的body结果一样
  91. //encodeString := base64.StdEncoding.EncodeToString(body)
  92. //fmt.Println("encodeString: ", encodeString)
  93. return_content.Body = body
  94. json_return_content, _ := json.Marshal(return_content) // body是base64编码
  95. ch <- json_return_content
  96. }
  97. func start() {
  98. ws, err := websocket.Dial(url, "", origin)
  99. for true {
  100. if err != nil {
  101. log.Fatal("err1 -> start: ", err)
  102. }
  103. var msg = make([]byte, 2048)
  104. m, err := ws.Read(msg)
  105. if err != nil {
  106. log.Fatal("err2 -> start: ", err)
  107. }
  108. web_message := msg[:m]
  109. //解析websocket发送的message
  110. var jx_web_message map[string]interface{}
  111. err = json.Unmarshal(web_message, &jx_web_message)
  112. if err != nil {
  113. log.Fatal("err3 -> start: ", err)
  114. }
  115. defer func() {
  116. ws.Close()
  117. }()
  118. go Forward(ws, jx_web_message)
  119. http_DO(jx_web_message)
  120. }
  121. }
  122. func main() {
  123. start()
  124. }

golang 反向代理的更多相关文章

  1. hasura的golang反向代理

    概述 反向代理代码 对请求的处理 对返回值的处理 遇到的问题 概述 一直在寻找一个好用的 graphql 服务, 之前使用比较多的是 prisma, 但是 prisma1 很久不再维护了, 而 pri ...

  2. golang 实现HTTP代理和反向代理

    正向代理 package main import ( "fmt" "io" "net" "net/http" " ...

  3. golang http proxy反向代理

    本文介绍golang中如何进行反向代理. 下面例子中, proxy server接收client 的 http request,转发给true server,并把 true server的返回结果再发 ...

  4. golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web

    golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web Nginx 部署 - beego: 简约 & 强大并存的 Go 应用框架https://bee ...

  5. IIS 反向代理 golang web开发

    一. beego 开发编译 bee run 后会编译成 exe文件 编译生成后发布文件结构为 cmd 运行 cd D:/run beegoDemo.exe run 默认配置端口 不能为 80 跟iis ...

  6. aProxy: 带认证授权和权限控制的反向代理

    前段时间很多数据库因为没有做好权限控制暴露在外网被删然后遭勒索的事件,而类似的有些内网的web服务也会被开放到公网并且没有做任何权限控制的,这样也会有一定的风险.所以就决定写篇文章简单介绍一个小工具. ...

  7. Nginx插件之openresty反向代理和日志滚动配置案例

    Nginx插件之openresty反向代理和日志滚动配置案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.openresty介绍 1>.Nginx介绍 Nginx是一款 ...

  8. prisma反向代理

    概要 为什么要做 prisma 的反向代理 反向代理示例(by golang) prisma 服务 gateway 服务 整体流程 认证 反向代理 权限 总结 概要 接触 prisma 有段时间了, ...

  9. Nginx-正反向代理及负载均衡

    目录 正/反向代理 代理的方式 Nginx代理服务支持的协议 代理实战 部署web01 部署Lb01 Nginx代理常用参数 添加发往后端服务器的请求头信息 代理到后端的TCP连接.响应.返回等超时时 ...

随机推荐

  1. SAX解析XML文档——(二)

    SAX从上向下解析,一行一行解析.节省内存,不适合CRUD. XML文档: <?xml version="1.0" encoding="UTF-8"?&g ...

  2. UML入门[转]

    访问权限控制 class Dummy { - private field1 # protected field2 ~ package method1() + public method2() } Al ...

  3. 【ARTS】01_11_左耳听风-20190121~20190127

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  4. 【转】inotify+rsync实现实时同步

    [转]inotify+rsync实现实时同步 1.1 什么是实时同步:如何实现实时同步 要利用监控服务(inotify),监控同步数据服务器目录中信息的变化 发现目录中数据产生变化,就利用rsync服 ...

  5. Kaggle Titanic补充篇

    1.关于年龄Age 除了利用平均数来填充,还可以利用正态分布得到一些随机数来填充,首先得到已知年龄的平均数mean和方差std,然后生成[ mean-std,  mean+std ]之间的随机数,然后 ...

  6. maven项目有红叉,感叹号如何解决?

    红色感叹号,pom.xml文件有红叉 修改了Maven私服服务器的IP地址.可在Maven安装路径下的conf/setting.xml中修改ip地址,具体参照“开发工具”/maven.工程中class ...

  7. CentOS7 虚拟机设置文件共享 VMWareTools安装遇到的坑

    设置文件共享的前提条件是已经安装好VMware Tools. 现在从安装VMware Tools开始讲起: 第一步:安装VMware Tools (如果安装的centos是最小安装,需要提前安装组件g ...

  8. HTTP SIP 认证

    HTTP请求报头: Authorization HTTP响应报头: WWW-Authenticate   HTTP认证  基于  质询  /回应(  challenge/response)的认证模式. ...

  9. [学习笔记]Java代码中各种类型变量的内存分配机制

    程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据: (1) 寄存器 这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部.然而 ...

  10. OneNET麒麟座应用开发之六:与气体质量流量控制器通讯

    气体质量流量控制器,简称MFC,通常用于在各种检测中,计量气体的流量.在我们的大气环境数据采集站中,要让气流保持稳定,这样才能准确的获取PM25的数据. 我们采用的气体质量流量控制器具备串口通讯功能, ...