服务器

package main

import (
"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 string
Header http.Header
Body []byte
Uri string
Host string
Id 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 := <-cp
ws.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...)
//出错就把标记表量设置为true
err_message = true
break
}
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.Request
var req Req_Group
req.Method = string(r.Method)
req.Header = r.Header
//使用随机字符串作为标识
req.Id = randomString(10)
defer r.Body.Close()
body, _ := ioutil.ReadAll(r.Body)
req.Body = body
req.Uri = r.URL.Path
req.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_chan
cp <- json_req new_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.Buffer
var temp string
for 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 := <-res
var 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 main

import (
"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_content
return_content.Id = Id
return_content.Uri = uri
return_content.Header = resp.Header
body, 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 = body
json_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发送的message
var 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 反向代理的更多相关文章

  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. Freemarker list 的简单使用

    freemarker list (长度,遍历,下标,嵌套,排序) 1. freemarker获取list的size : Java ArrayList<String> list = new ...

  2. 使用xmanager图形化远程连接rhel6

    使用xmanager图形化远程连接rhel6 xmanager中Xbrowser可以提供图形化桌面远程.和vnc比,可以类似于本地一样用户切换. 操作步骤: linux服务端: 1:查看/etc/in ...

  3. 【网络编程2】网络编程基础-发送ICMP包(Ping程序)

    IP协议 网络地址和主机协议 位于网络层的协议,主要目的是使得网络能够互相通信,该协议使用逻辑地址跨网络通信,目前有两个版本IPV4,IPV6. 在IPV4协议中IP地址是一个32位的数备,采用点分四 ...

  4. tomcat启动报错 ERROR o.a.catalina.session.StandardManager 182 - Exception loading sessions from persiste

    系统:centos6.5 x86_64 jdk: 1.8.0_102 tomcat:8.0.37 tomcat 启动报错: ERROR o.a.catalina.session.StandardMan ...

  5. zabbix系列(八)zabbix添加对web页面url的状态监控

    通过zabbi做web监控不仅仅可以监控到站点的响应时间,还可以根据站点返回的状态码,或者响应时间做报警 1.对需要监控的主机添加web监控   在configuration—hosts 中打开主机列 ...

  6. Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)

    1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...

  7. 让Linux任务在后台可靠运行的几种方法

      我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败.如何让命令提交后不受本地关闭终端窗口/网络 ...

  8. su和sudo命令详解

    我们知道,在Linux下对很多文件进行修改都需要有root(管理员)权限,比如对/ect/profile等文件的修改.很多情况下,我们在进行开发的时候都是使用普通用户进行登录的,尤其在进行一些环境变量 ...

  9. OCM_第十二天课程:Section6 —》数据库性能调优_ 资源管理器/执行计划

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

  10. C++ one more time

    写在前面:我们学习程序设计的方法先是模仿,然后举一反三.在自己的知识面还没有铺开到足够解决本领域的问题时,不要将精力过分集中于对全局无足轻重的地方!!! 以下参考钱能老师的<C++程序设计教程 ...