最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一個(gè)簡(jiǎn)單的Golang實(shí)現(xiàn)的HTTP Proxy方法

 更新時(shí)間:2019年08月22日 13:47:48   作者:飛雪無(wú)情  
今天小編就為大家分享一篇一個(gè)簡(jiǎn)單的Golang實(shí)現(xiàn)的HTTP Proxy方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

最近因?yàn)閾Q了Mac,以前的Linux基本上不再使用了,但是我的SS代理還得用。SS代理大家都了解,一個(gè)很NB的socks代理工具,但是就是因?yàn)樗荢ocks的,想用HTTP代理的時(shí)候很不方便。

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

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

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

啟動(dòng)代理監(jiān)聽(tīng)

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

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

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

監(jiān)聽(tīng)接收代理請(qǐng)求

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

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

    go handleClientRequest(client)
  }

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

解析請(qǐng)求,獲取要訪問(wèn)的IP和端口

有了客戶端的代理請(qǐng)求了,我們還得從請(qǐng)求里提取客戶端要訪問(wèn)的遠(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

可以看到我們需要的在第一行,第一個(gè)行的信息以空格分開(kāi),第一部分CONNECT是請(qǐng)求方法,這里是CONNECT,除此之外還有GET,POST等,都是HTTP協(xié)議的標(biāo)準(zhǔn)方法。

第二部分是URL,https的請(qǐng)求只有host和port,http的請(qǐng)求是一個(gè)完成的url,等下會(huì)看個(gè)樣例,就明白了。

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

以上是一個(gè)https的請(qǐng)求,我們看下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的,沒(méi)有端口號(hào)(默認(rèn)是80);比https多了schame–http://。

有了分析,下面我們就可以從HTTP頭信息中獲取請(qǐng)求的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)一步對(duì)url進(jìn)行解析,獲取我們需要的遠(yuǎn)程服務(wù)器信息


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

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

ip:port
hostname:port
domainname:port

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

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

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

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

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

撥號(hào)成功后,就可以進(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)

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

運(yùn)行外國(guó)外VPS上

到這里,我們的代理服務(wù)器全部開(kāi)發(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訪問(wèn)
    address = hostPortURL.Scheme + ":443"
  } else { //http訪問(wèn)
    if strings.Index(hostPortURL.Host, ":") == -1 { //host不帶端口, 默認(rèn)80
      address = hostPortURL.Host + ":80"
    } else {
      address = hostPortURL.Host
    }
  }

  //獲得了請(qǐng)求的host和port,就開(kāi)始撥號(hào)吧
  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)
}

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

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

相關(guān)文章

  • Go語(yǔ)言等待組sync.WaitGrou的使用示例

    Go語(yǔ)言等待組sync.WaitGrou的使用示例

    本文主要介紹了Go語(yǔ)言等待組sync.WaitGrou的使用示例,sync.WaitGroup只有3個(gè)方法,Add(),Done(),Wait(),下面就來(lái)具體的介紹一下如何使用,感興趣的可以了解一下
    2024-08-08
  • 淺析Golang中的net/http路由注冊(cè)與請(qǐng)求處理

    淺析Golang中的net/http路由注冊(cè)與請(qǐng)求處理

    這篇文章主要為大家詳細(xì)介紹了Golang中的net/http路由注冊(cè)與請(qǐng)求處理的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • go?閉包c(diǎn)ase示例代碼

    go?閉包c(diǎn)ase示例代碼

    這篇文章解釋了Go語(yǔ)言中匿名函數(shù)、閉包、立即執(zhí)行函數(shù)表達(dá)式(IIFE)和變量作用域的概念,它通過(guò)一個(gè)示例代碼展示了匿名函數(shù)如何捕獲并修改外部變量,以及如何使用立即執(zhí)行函數(shù)表達(dá)式來(lái)立即執(zhí)行這個(gè)匿名函數(shù),感興趣的朋友一起看看吧
    2025-02-02
  • Golang使用Decimal庫(kù)避免運(yùn)算中精度損失詳細(xì)步驟

    Golang使用Decimal庫(kù)避免運(yùn)算中精度損失詳細(xì)步驟

    decimal是為了解決Golang中浮點(diǎn)數(shù)計(jì)算時(shí)精度丟失問(wèn)題而生的一個(gè)庫(kù),使用decimal庫(kù)我們可以避免在go中使用浮點(diǎn)數(shù)出現(xiàn)精度丟失的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于Golang使用Decimal庫(kù)避免運(yùn)算中精度損失的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • Golang匯編之控制流深入分析講解

    Golang匯編之控制流深入分析講解

    這篇文章主要介紹了Golang匯編之控制流,程序執(zhí)行的流程主要有順序、分支和循環(huán)幾種執(zhí)行流程,本節(jié)主要討論如何將Go語(yǔ)言的控制流比較直觀地轉(zhuǎn)譯為匯編程序,或者說(shuō)如何以匯編思維來(lái)編寫(xiě)Go語(yǔ)言代碼,感興趣的同學(xué)可以參考下文
    2023-05-05
  • Golang語(yǔ)言學(xué)習(xí)拿捏Go反射示例教程

    Golang語(yǔ)言學(xué)習(xí)拿捏Go反射示例教程

    這篇文章主要為大家介紹了Golang語(yǔ)言中Go反射示例的教程,教你拿捏Go反射,再也不用被Go反射折磨,有需要的朋友可以共同學(xué)習(xí)參考下
    2021-11-11
  • Go語(yǔ)言中一些不常見(jiàn)的命令參數(shù)詳解

    Go語(yǔ)言中一些不常見(jiàn)的命令參數(shù)詳解

    這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中一些不常見(jiàn)的命令參數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • go使用snmp庫(kù)查詢mib數(shù)據(jù)案例代碼

    go使用snmp庫(kù)查詢mib數(shù)據(jù)案例代碼

    go語(yǔ)言使用snmp庫(kù)中的 k-sone/snmpgo 實(shí)現(xiàn)相關(guān)mib查詢,本文通過(guò)實(shí)例代碼給大家介紹了go使用snmp庫(kù)查詢mib數(shù)據(jù),感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)

    golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)

    這篇文章主要介紹了golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 如何使用go-zero開(kāi)發(fā)線上項(xiàng)目

    如何使用go-zero開(kāi)發(fā)線上項(xiàng)目

    這篇文章主要介紹了如何使用go-zero開(kāi)發(fā)線上項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論

兖州市| 登封市| 长宁县| 平邑县| 阳城县| 鸡东县| 顺昌县| 平昌县| 牟定县| 洛川县| 九龙县| 新兴县| 罗江县| 麻栗坡县| 阳高县| 绥化市| 永春县| 闻喜县| 孝昌县| 永德县| 烟台市| 静乐县| 庄浪县| 芦山县| 崇明县| 沙湾县| 松滋市| 博客| 玉溪市| 石渠县| 章丘市| 南汇区| 海南省| 遂昌县| 内丘县| 郓城县| 泾阳县| 吉安市| 兴和县| 邹平县| 墨竹工卡县|