婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 一個簡單的Golang實現(xiàn)的HTTP Proxy方法

一個簡單的Golang實現(xiàn)的HTTP Proxy方法

熱門標(biāo)簽:廣州呼叫中心外呼系統(tǒng) 江西轉(zhuǎn)化率高的羿智云外呼系統(tǒng) 地圖標(biāo)注的汽車標(biāo) 中國地圖標(biāo)注省會高清 西部云谷一期地圖標(biāo)注 浙江高速公路地圖標(biāo)注 南通如皋申請開通400電話 學(xué)海導(dǎo)航地圖標(biāo)注 高德地圖標(biāo)注口訣

最近因為換了Mac,以前的Linux基本上不再使用了,但是我的SS代理還得用。SS代理大家都了解,一個很NB的socks代理工具,但是就是因為他是Socks的,想用HTTP代理的時候很不方便。

以前在Linux下的時候,會安裝一個Privoxy把socks代理轉(zhuǎn)換為HTTP代理,開機(jī)啟動,也比較方便。但是Mac下使用Brew安裝的Privoxy就很難用,再加上以前一個有個想法,一個軟件搞定socks和HTTP代理,這樣就不用安裝一個單獨的軟件做轉(zhuǎn)換了。

想著就開始做吧,以前基本上沒有搞過太多的網(wǎng)絡(luò)編程,最近也正好在研究Go,正好練練手。

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

啟動代理監(jiān)聽

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

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

以上代理我們就實現(xiàn)了一個在8080端口上監(jiān)聽的服務(wù)器,我們這里沒有寫ip地址,默認(rèn)在所有ip地址上進(jìn)行監(jiān)聽。如果你只想本機(jī)適用,可以使用127.0.0.1:8080,這樣機(jī)器就訪問不了你的代理服務(wù)器了。

監(jiān)聽接收代理請求

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

  for {
    client, err := l.Accept()
    if err != nil {
      log.Panic(err)
    }

    go handleClientRequest(client)
  }

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

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

有了客戶端的代理請求了,我們還得從請求里提取客戶端要訪問的遠(yuǎn)程主機(jī)的IP和端口,這樣我們的代理服務(wù)器才可以建立和遠(yuǎn)程主機(jī)的連接,代理轉(zhuǎn)發(fā)。

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

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協(xié)議的標(biāo)準(zhǔn)方法。

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

第三部是HTTP的協(xié)議和版本,這個我們不用太關(guān)注。

以上是一個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的,沒有端口號(默認(rèn)是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
  
  }

然后需要進(jìn)一步對url進(jìn)行解析,獲取我們需要的遠(yuǎn)程服務(wù)器信息


  if hostPortURL.Opaque == "443" { //https訪問
    address = hostPortURL.Scheme + ":443"
  } else { //http訪問
    if strings.Index(hostPortURL.Host, ":") == -1 { //host不帶端口, 默認(rèn)80
      address = hostPortURL.Host + ":80"
    } else {
      address = hostPortURL.Host
    }
  }

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

ip:port
hostname:port
domainname:port

就是有可能是ip(v4orv6),有可能是主機(jī)名(內(nèi)網(wǎng)),有可能是域名(dns解析)

代理服務(wù)器和遠(yuǎn)程服務(wù)器建立連接

有了遠(yuǎn)程服務(wù)器的信息了,就可以進(jìn)行撥號建立連接了,有了連接,才可以通信。

  //獲得了請求的host和port,就開始撥號吧
  server, err := net.Dial("tcp", address)
  if err != nil {
    log.Println(err)
    return
  }

數(shù)據(jù)轉(zhuǎn)發(fā)

撥號成功后,就可以進(jìn)行數(shù)據(jù)代理傳輸了

if method == "CONNECT" {
    fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")
  } else {
    server.Write(b[:n])
  }
  //進(jìn)行轉(zhuǎn)發(fā)
  go io.Copy(server, client)
  io.Copy(client, server)

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

運行外國外VPS上

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

package main

import (
  "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不帶端口, 默認(rèn)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])
  }
  //進(jìn)行轉(zhuǎn)發(fā)
  go io.Copy(server, client)
  io.Copy(client, server)
}

把源代碼編譯,然后放到你國外的VPS上,在自己機(jī)器上配置好HTTP代理,就可以到處訪問,自由自在了。

以上這篇一個簡單的Golang實現(xiàn)的HTTP Proxy方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • Golang 實現(xiàn)分片讀取http超大文件流和并發(fā)控制
  • 解決golang處理http response碰到的問題和需要注意的點
  • golang實現(xiàn)http server提供文件下載功能
  • Golang 發(fā)送http請求時設(shè)置header的實現(xiàn)
  • golang使用http client發(fā)起get和post請求示例
  • 在 Golang 中實現(xiàn)一個簡單的Http中間件過程詳解

標(biāo)簽:吐魯番 東營 保定 常州 許昌 德宏 貴州 曲靖

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《一個簡單的Golang實現(xiàn)的HTTP Proxy方法》,本文關(guān)鍵詞  一個,簡單,的,Golang,實現(xiàn),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《一個簡單的Golang實現(xiàn)的HTTP Proxy方法》相關(guān)的同類信息!
  • 本頁收集關(guān)于一個簡單的Golang實現(xiàn)的HTTP Proxy方法的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    主站蜘蛛池模板: 绥德县| 巧家县| 泊头市| 牟定县| 贡觉县| 双鸭山市| 大荔县| 阜南县| 务川| 轮台县| 门源| 灌阳县| 佳木斯市| 合江县| 鹰潭市| 民乐县| 乌什县| 长治县| 陆川县| 邢台市| 徐汇区| 平罗县| 南乐县| 四子王旗| 永城市| 杨浦区| 营山县| 淳化县| 织金县| 中宁县| 肃南| 且末县| 车险| 巴青县| 河津市| 望都县| 德阳市| 西平县| 上饶县| 西宁市| 大关县|