本篇概要:
1. 反向代理;
正向代理:
反向代理:
2. 利用协程创建两个测试服务;
# 进入 /Users/go/src/com.proxy/
go mod init proxy.test.com
- 文件
/Users/go/src/com.proxy/webmain.go
package main
import (
"log"
"net/http"
"os"
"os/signal"
)
type web1handler struct {
}
func (web1handler) ServeHTTP (writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("web1"))
}
type web2handler struct {
}
func (web2handler) ServeHTTP (writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("web2"))
}
func main() {
// channel 阻塞,或者监听信号,否则运行直接退出
c := make(chan os.Signal) // 信号
// 通过反向代理去访问 9091 或者 9092
go func() {
http.ListenAndServe(":9091", web1handler{})
}()
go func() {
http.ListenAndServe(":9092", web2handler{})
}()
signal.Notify(c, os.Interrupt)
s :=<- c // c 信号传递给 s 变量
log.Println(s)
}
3. 最简单的请求 “转发” 、httpclient 使用;
- 文件
/Users/go/src/com.proxy/myproxy.go
package main
import (
"io/ioutil"
"log"
"net/http"
)
type ProxyHandler struct {
}
func(* ProxyHandler) ServeHTTP (w http.ResponseWriter, r *http.Request) {
// fmt.Println(r.RequestURI) // "/" 后面的所有参数
//fmt.Println(r.URL.Path) // "/" 后面的部分,不带参数
//w.Write([]byte("test"))
defer func() {
if err := recover(); err != nil {
w.WriteHeader(500)
log.Println(err)
}
}()
if r.URL.Path == "/a" {
// http.Get() 不能直接写 get 或是 post,因为不知道用户是什么请求
// 使用原始函数
newreq, _ := http.NewRequest(r.Method, "http://localhost:9091", r.Body) // 地址暂时写死
// 根据 request 获取 response响应对象
newresponse, _ := http.DefaultClient.Do(newreq)
defer newresponse.Body.Close()
// 读取 body
res_cont, _ := ioutil.ReadAll(newresponse.Body)
w.Write(res_cont)
return
}
w.Write([]byte("default index"))
}
func main() {
http.ListenAndServe(":8080",&ProxyHandler{})
}
4. 在 httpserver 中实现 Basic Auth 的认证和解析;
- 文件
/Users/go/src/com.proxy/webmain.go
package main
import (
"encoding/base64"
"log"
"net/http"
"os"
"os/signal"
"strings"
)
type web1handler struct {
}
func (web1handler) ServeHTTP (writer http.ResponseWriter, request *http.Request) {
auth:=request.Header.Get("Authorization")
if auth == "" {
writer.Header().Set("WWW-Authenticate", `Basic realm="您必须输入用户名和密码"`) // 反单引号
writer.WriteHeader(http.StatusUnauthorized)
return
}
//str := "hua:123"
// 编码
//fmt.Println(base64.StdEncoding.EncodeToString([]byte(str))) //aHVhOjEyMw==
// 解码
// base64.StdEncoding.DecodeString()
// 因为发送请求时添加头 Authorization: Basic aHVhOjEyMw== (一个空格)
auth_list:=strings.Split(auth," ")
if len(auth_list) == 2 && auth_list[0] == "Basic" {
res, err := base64.StdEncoding.DecodeString(auth_list[1])
if err == nil && string(res) == "hua:123" {
writer.Write([]byte("<h1>web1</h1>"))
return
}
}
writer.Write([]byte("用户名密码错误"))
}
type web2handler struct {
}
func (web2handler) ServeHTTP (writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("web2"))
}
func main() {
// channel 阻塞,或者监听信号,否则运行直接退出
c := make(chan os.Signal) // 信号
// 通过反向代理去访问 9091 或者 9092
go func() {
http.ListenAndServe(":9091", web1handler{})
}()
go func() {
http.ListenAndServe(":9092", web2handler{})
}()
signal.Notify(c, os.Interrupt)
s :=<- c // c 信号传递给 s 变量
log.Println(s)
}
5. 反向代理支持 Basic Auth 验证框弹出;
- 文件
/Users/go/src/com.proxy/util/functions.go
package util
import "net/http"
func CloneHeader(src http.Header, dest *http.Header) {
for k,v := range src{
dest.Set(k, v[0])
}
}
- 文件
/Users/go/src/com.proxy/myproxy.go
package main
import (
"io/ioutil"
"log"
"net/http"
. "proxy.test.com/util"
)
type ProxyHandler struct {
}
func(* ProxyHandler) ServeHTTP (w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
w.WriteHeader(500)
log.Println(err)
}
}()
if r.URL.Path == "/a" {
// http.Get() 不能直接写 get 或是 post,因为不知道用户是什么请求
// 使用原始函数
newreq, _ := http.NewRequest(r.Method, "http://localhost:9091", r.Body) // 地址暂时写死
// 根据 request 获取 response响应对象
newresponse, _ := http.DefaultClient.Do(newreq)
// 拷贝头
getHeader := w.Header()
CloneHeader(newresponse.Header, &getHeader)
w.WriteHeader(newresponse.StatusCode) // 写入http status
defer newresponse.Body.Close()
// 读取 body
res_cont, _ := ioutil.ReadAll(newresponse.Body)
w.Write(res_cont)
return
}
w.Write([]byte("default index"))
}
func main() {
http.ListenAndServe(":8080",&ProxyHandler{})
}