zoukankan      html  css  js  c++  java
  • 一个利用go*解决api转发的例子(go*)

    实现的效果:

    如果访问的url路径是类似 /163/  或 /163/debian 的形式,则转发到163开源镜像服务器

    直接上代码:

    package main
    
    import (
        "fmt"
        "log"
        "net/http"
        "net/http/httputil"
        "net/url"
    )
    
    var fwdHost = "mirrors.163.com"  //http首部字段的HOST取值
    var fwdTo = "http://" + fwdHost + "/"
    var fwdPrefix = "/163/"
    
    type forward struct {
        RProxy *httputil.ReverseProxy
    }
    
    func (f *forward) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
        //fmt.Printf("http头部是:%+v
    ", req.Header) //假设这是处理http头部的代码
        fmt.Printf(" #### REQ:%+v
    ", req)
    
        //处理完后转发到网易163镜像
        req.URL.Path = req.URL.Path[len(fwdPrefix)-1:] //修改了这里,req.RequestURI会跟着变
        req.Host = fwdHost
        fmt.Printf(" *** REQ:%+v
    ", req)
        f.RProxy.ServeHTTP(wr, req)
    }
    
    func main() {
        var fwd forward
        u, _ := url.Parse(fwdTo)
        fwd.RProxy = httputil.NewSingleHostReverseProxy(u)
        http.Handle(fwdPrefix, &fwd) //所有请求将转发到网易163的debian镜像
        http.HandleFunc("/", notForward)
        http.HandleFunc("/api/v1/", notForward)
        log.Fatal(http.ListenAndServe(":3000", nil))
    }
    
    func notForward(wr http.ResponseWriter, req *http.Request) {
        wr.Write([]byte(fmt.Sprintf(`<html>
    <body>
          <em>Not forward!!</em>
          <br />
          <i>url = %s</i>
    </body>
    </html>
    `,req.URL.String())))
    }

    类似的还有更简单的做法,关键在httputil.ReverseProxy的Director字段

    func APIReverseProxy(host string) http.HandlerFunc {
        var rp = httputil.ReverseProxy{
            Director:func(req *http.Request) {
                req.URL.Scheme = "http"
    req.URL.Host = host
    req.Host = host //对于一个ip地址托管多个域名的情况下,必须要给req.Host赋值,如果一个ip地址只有一个域名,可以不写这一句 //req.URL.Path = //如果需要改path的话 }, } return func(wr http.ResponsWriter, req *http.Request){ rp.ServeHTTP(wr,req) } //这里是返回http.HandlerFunc的例子,其实也可以直接返回rp(因为*rp就是一个http.Handler, *rp实现了ServeHTTP(wr,req)方法) }

    关于req.URL.Host和req.Host:

    go http包中对request中Host的注释:

    // For server requests Host specifies the host on which the
    // URL is sought. Per RFC 2616, this is either the value of
    // the "Host" header or the host name given in the URL itself.
    // It may be of the form "host:port". For international domain
    // names, Host may be in Punycode or Unicode form. Use
    // golang.org/x/net/idna to convert it to either format if
    // needed.
    //
    // For client requests Host optionally overrides the Host
    // header to send. If empty, the Request.Write method uses
    // the value of URL.Host. Host may contain an international
    // domain name.
    Host string

    另外:
    req.URL.Host是从URL中解析出来的,
    req.Host是http请求头部"Host" , 这个头部用于实现虚拟主机(一个ip托管多个域名),http1.1规范中,Host头是必须存在的

    对于下面的请求:
    GET /index.html HTTP/1.1
    Host: www.example.org:8080
    req.URL.Host是空的
    对于通过代理的请求,req.URL.Host是目标主机,req.Host是代理服务器。
    对于不是走代理的请求,req.URL.Host是空的,req.Host是目标主机

  • 相关阅读:
    【SqlServer系列】表达式(expression)
    【SqlServer系列】语法定义符号解析
    Docker常用命令<转>
    VMware下的Centos7联网并设置固定IP
    redis的setbit命令
    Java并发编程:并发容器之CopyOnWriteArrayList<转>
    Java并发编程:volatile关键字解析<转>
    Java并发编程:阻塞队列 <转>
    Java并发编程:Lock和Synchronized <转>
    Jackson学习笔记(三)<转>
  • 原文地址:https://www.cnblogs.com/mind-water/p/11061034.html
Copyright © 2011-2022 走看看