91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Go語言實現一個HTTP代理

發布時間:2022-04-21 14:12:59 來源:億速云 閱讀:663 作者:iii 欄目:大數據

這篇文章主要講解了“怎么用Go語言實現一個HTTP代理”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么用Go語言實現一個HTTP代理”吧!

怎么用Go語言實現一個HTTP代理

我們這里主要講使用HTTP/1.1協議中的CONNECT方法建立起來的隧道連接,實現的HTTP Proxy。這種代理的好處就是不用知道客戶端請求的數據,只需要原封不動的轉發就可以了,對于處理HTTPS的請求就非常方便了,不用解析他的內容,就可以實現代理。

啟動代理監聽

要想做一個HTTP Proxy,我們需要啟動一個服務器,監聽一個端口,用于接收客戶端的請求。Golang給我們提供了強大的net包供我們使用,我們啟動一個代理服務器監聽非常方便。

    l, err := net.Listen("tcp", ":8080")    if err != nil {

        log.Panic(err)

    }

以上代理我們就實現了一個在8080端口上監聽的服務器,我們這里沒有寫ip地址,默認在所有ip地址上進行監聽。如果你只想本機適用,可以使用127.0.0.1:8080,這樣機器就訪問不了你的代理服務器了。

監聽接收代理請求

啟動了代理服務器,就可以開始接受不了代理請求了,有了請求,我們才能做進一步的處理。

    for {

        client, err := l.Accept()        if err != nil {

            log.Panic(err)

        }        go handleClientRequest(client)

    }

Listener接口的Accept方法,會接受客戶端發來的連接數據,這是一個阻塞型的方法,如果客戶端沒有連接數據發來,他就是阻塞等待。接收來的連接數據,會馬上交給handleClientRequest方法進行處理,這里使用一個go關鍵字開一個goroutine的目的是不阻塞客戶端的接收,代理服務器可以馬上接收下一個連接請求。

解析請求,獲取要訪問的IP和端口

有了客戶端的代理請求了,我們還得從請求里提取客戶端要訪問的遠程主機的IP和端口,這樣我們的代理服務器才可以建立和遠程主機的連接,代理轉發。

HTTP協議的頭信息里就包含有我們需要的主機名(IP)和端口信息,并且是明文的,協議很規范,類似于:

CONNECT www.google.com:443 HTTP/1.1

Host: www.google.com:443

Proxy-Connection: keep-alive

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36

可以看到我們需要的在第一行,第一個行的信息以空格分開,第一部分CONNECT是請求方法,這里是CONNECT,除此之外還有GET,POST等,都是HTTP協議的標準方法。

第二部分是URL,https的請求只有host和port,http的請求是一個完成的url,等下會看個樣例,就明白了。

第三部是HTTP的協議和版本,這個我們不用太關注。

以上是一個https的請求,我們看下http的:

GET http://www.flysnow.org/ HTTP/1.1

Host: www.flysnow.org

Proxy-Connection: keep-alive

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36

可以看到htt的,沒有端口號(默認是80);比https多了schame—http://。

有了分析,下面我們就可以從HTTP頭信息中獲取請求的url和method信息了。

    var b [1024]byte

    n, err := client.Read(b[:])    if err != nil {

        log.Println(err)        return

    }    var method, host, address string

    fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)

    hostPortURL, err := url.Parse(host)    if err != nil {

        log.Println(err)        return

    }

然后需要進一步對url進行解析,獲取我們需要的遠程服務器信息

    if hostPortURL.Opaque == "443" { //https訪問

        address = hostPortURL.Scheme + ":443"

    } else { //http訪問

        if strings.Index(hostPortURL.Host, ":") == -1 { //host不帶端口, 默認80

            address = hostPortURL.Host + ":80"

        } else {

            address = hostPortURL.Host

        }

    }

這樣就完整了獲取了要請求服務器的信息,他們可能是以下幾種格式

ip:port

hostname:port

domainname:port

就是有可能是ip(v4orv6),有可能是主機名(內網),有可能是域名(dns解析)

代理服務器和遠程服務器建立連接

有了遠程服務器的信息了,就可以進行撥號建立連接了,有了連接,才可以通信。

    //獲得了請求的host和port,就開始撥號吧

    server, err := net.Dial("tcp", address)    if err != nil {

        log.Println(err)        return

    }

數據轉發

撥號成功后,就可以進行數據代理傳輸了

if method == "CONNECT" {

        fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")

    } else {

        server.Write(b[:n])

    }    //進行轉發

    go io.Copy(server, client)

    io.Copy(client, server)

其中對CONNECT方法有單獨的回應,客戶端說要建立連接,代理服務器要回應建立好了,然后才可以像HTTP一樣請求訪問。

完整代碼

到這里,我們的代理服務器全部開發完成了,下面是完整的源代碼:

package mainimport (    "bytes"

    "fmt"

    "io"

    "log"

    "net"

    "net/url"

    "strings")func main() {

    log.SetFlags(log.LstdFlags|log.Lshortfile)

    l, err := net.Listen("tcp", ":8081")    if err != nil {

        log.Panic(err)

    }    for {

        client, err := l.Accept()        if err != nil {

            log.Panic(err)

        }        go handleClientRequest(client)

    }

}func handleClientRequest(client net.Conn) {    if client == nil {        return

    }    defer client.Close()    var b [1024]byte

    n, err := client.Read(b[:])    if err != nil {

        log.Println(err)        return

    }    var method, host, address string

    fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)

    hostPortURL, err := url.Parse(host)    if err != nil {

        log.Println(err)        return

    }    if hostPortURL.Opaque == "443" { //https訪問

        address = hostPortURL.Scheme + ":443"

    } else { //http訪問

        if strings.Index(hostPortURL.Host, ":") == -1 { //host不帶端口, 默認80

            address = hostPortURL.Host + ":80"

        } else {

            address = hostPortURL.Host

        }

    }    //獲得了請求的host和port,就開始撥號吧

    server, err := net.Dial("tcp", address)    if err != nil {

        log.Println(err)        return

    }    if method == "CONNECT" {

        fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")

    } else {

        server.Write(b[:n])

    }    //進行轉發

    go io.Copy(server, client)

    io.Copy(client, server)

}

感謝各位的閱讀,以上就是“怎么用Go語言實現一個HTTP代理”的內容了,經過本文的學習后,相信大家對怎么用Go語言實現一個HTTP代理這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

张家界市| 乌什县| 论坛| 金昌市| 柳林县| 定兴县| 阿克苏市| 美姑县| 竹溪县| 泊头市| 定边县| 济阳县| 墨江| 厦门市| 祁阳县| 都安| 蚌埠市| 汤阴县| 新邵县| 四川省| 龙里县| 天峨县| 晴隆县| 长岛县| 泰州市| 屏边| 新田县| 汝州市| 彰武县| 虎林市| 温宿县| 邵阳县| 孝义市| 武冈市| 同仁县| 高密市| 沙雅县| 闵行区| 广州市| 宝兴县| 南木林县|