那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

http代理概述及代碼實現方法

馬哥Linux運維 ? 來源:staight.github.io ? 作者:staight.github.io ? 2022-05-14 15:02 ? 次閱讀

本文詳細介紹了Golang 實現 http 代理的實現,在實際業務中有需求的同學可以學起來了!

代理是網絡中的一項重要的功能,其功能就是代理網絡用戶去取得網絡信息。形象的說:它是網絡信息的中轉站,對于客戶端來說,代理扮演的是服務器的角色,接收請求報文,返回響應報文;對于 web 服務器來說,代理扮演的是客戶端的角色,發送請求報文,接收響應報文。

代理具有多種類型,如果是根據網絡用戶劃分的話,可以劃分為正向代理和反向代理:

  • 正向代理:將客戶端作為網絡用戶??蛻舳嗽L問服務端時,先訪問代理服務器,隨后代理服務器再訪問服務端。此過程需客戶端進行代理配置,對服務端透明。
  • 反向代理:將服務端作為網絡用戶。訪問過程與正向代理相同,不過此過程對客戶端透明,需服務端進行代理配置(也可不配置)。

針對正向代理和反向代理,分別有不同的代理協議,即代理服務器和網絡用戶之間通信所使用的協議:

  • 正向代理:
    • http
    • https
    • socks4
    • socks5
    • vpn:就功能而言,vpn 也可以被認為是代理
  • 反向代理:
    • tcp
    • udp
    • http
    • https

接下來我們就說說 http 代理。

http 代理概述

http 代理是正向代理中較為簡單的代理方式,它使用 http 協議作為客戶端和代理服務器的傳輸協議。

http 代理可以承載 http 協議,https 協議,ftp 協議等等。對于不同的協議,客戶端和代理服務器間的數據格式略有不同。

http 協議

我們先來看看 http 協議下客戶端發送給代理服務器的 HTTP Header:

// 直接連接GET / HTTP/1.1Host: staight.github.ioConnection: keep-alive
// http 代理GET http://staight.github.io/ HTTP/1.1Host: staight.github.ioProxy-Connection: keep-alive

		

可以看到,http 代理比起直接連接:

  • url 變成完整路徑,/->http://staight.github.io/
  • Connection字段變成Proxy-Connection字段
  • 其余保持原樣

為什么使用完整路徑?

為了識別目標服務器。如果沒有完整路徑,且沒有 Host 字段的話,代理服務器將無法得知目標服務器的地址。

為什么使用 Proxy-Connection 字段代替 Connection 字段?

為了兼容使用 HTTP/1.0 協議的過時的代理服務器。HTTP/1.1 才開始有長連接功能,直接連接的情況下,客戶端發送的 HTTP Header 中如果有Connection: keep-alive字段,表示使用長連接和服務端進行 http 通信,但如果中間有過時的代理服務器,該代理服務器將無法與客戶端和服務端進行長連接,造成客戶端和服務端一直等待,白白浪費時間。

因此使用Proxy-Connection字段代替Connection字段,如果代理服務器使用 HTTP/1.1 協議,能夠識別Proxy-Connection字段,則將該字段轉換成Connection再發送給服務端;如果不能識別,直接發送給服務端,因為服務端也無法識別,則使用短連接進行通信。

http 代理 http 協議交互過程如圖:

79e26f24-d2c2-11ec-bce3-dac502259ad0.png

http 代理 http 協議

https 協議

接下來我們來看看 https 協議下,客戶端發送給代理服務器的 HTTP Header:

CONNECT staight.github.io:443 HTTP/1.1Host: staight.github.io:443Proxy-Connection: keep-alive

		

如上,https 協議和 http 協議相比:

  • 請求方法從GET變成CONNECT
  • url 沒有 protocol 字段

實際上,由于 https 下客戶端和服務端的通信除了開頭的協商以外都是密文,中間的代理服務器不再承擔修改 http 報文再轉發的功能,而是一開始就和客戶端協商好服務端的地址,隨后的 tcp 密文直接轉發即可。

http 代理 https 協議交互過程如圖:

7a2228b2-d2c2-11ec-bce3-dac502259ad0.png

http 代理 https 協議

代碼實現

首先,創建 tcp 服務,并且對于每個 tcp 請求,均調用 handle 函數:

// tcp 連接,監聽 8080 端口l, err := net.Listen("tcp", ":8080")if err != nil { log.Panic(err)}
// 死循環,每當遇到連接時,調用 handlefor { client, err := l.Accept() if err != nil {  log.Panic(err) }
 go handle(client)   }

		

然后將獲取的數據放入緩沖區:

// 用來存放客戶端數據的緩沖區var b [1024]byte//從客戶端獲取數據n, err := client.Read(b[:])if err != nil { log.Println(err) return   }

		

從緩沖區讀取 HTTP 請求方法,URL 等信息:

var method, URL, address string// 從客戶端數據讀入 method,urlfmt.Sscanf(string(b[:bytes.IndexByte(b[:], '
')]), "%s%s", &method, &URL)hostPortURL, err := url.Parse(URL)if err != nil { log.Println(err) return   }

http 協議和 https 協議獲取地址的方式不同,分別處理:

// 如果方法是 CONNECT,則為 https 協議if method == "CONNECT" { address = hostPortURL.Scheme + ":" + hostPortURL.Opaque} else { //否則為 http 協議 address = hostPortURL.Host // 如果 host 不帶端口,則默認為 80 if strings.Index(hostPortURL.Host, ":") == -1 { //host 不帶端口, 默認 80  address = hostPortURL.Host + ":80" }   }

		

用獲取到的地址向服務端發起請求。如果是 http 協議,將客戶端的請求直接轉發給服務端;如果是 https 協議,發送 http 響應:

//獲得了請求的 host 和 port,向服務端發起 tcp 連接server, err := net.Dial("tcp", address)if err != nil { log.Println(err) return}//如果使用 https 協議,需先向客戶端表示連接建立完畢if method == "CONNECT" { fmt.Fprint(client, "HTTP/1.1 200 Connection established

")} else { //如果使用 http 協議,需將從客戶端得到的 http 請求轉發給服務端 server.Write(b[:n])   }

		

最后,將所有客戶端的請求轉發至服務端,將所有服務端的響應轉發給客戶端:

//將客戶端的請求轉發至服務端,將服務端的響應轉發給客戶端。io.Copy 為阻塞函數,文件描述符不關閉就不停止go io.Copy(server, client)   io.Copy(client, server

		

完整的源代碼:

package main
import ( "bytes" "fmt" "io" "log" "net" "net/url" "strings")
func main() { // tcp 連接,監聽 8080 端口 l, err := net.Listen("tcp", ":8080") if err != nil {  log.Panic(err) }
 // 死循環,每當遇到連接時,調用 handle for {  client, err := l.Accept()  if err != nil {   log.Panic(err)  }
  go handle(client) }}
func handle(client net.Conn) { if client == nil {  return } defer client.Close()
 log.Printf("remote addr: %v
", client.RemoteAddr())
 // 用來存放客戶端數據的緩沖區 var b [1024]byte //從客戶端獲取數據 n, err := client.Read(b[:]) if err != nil {  log.Println(err)  return }
 var method, URL, address string // 從客戶端數據讀入 method,url fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '
')]), "%s%s", &method, &URL) hostPortURL, err := url.Parse(URL) if err != nil {  log.Println(err)  return }
 // 如果方法是 CONNECT,則為 https 協議 if method == "CONNECT" {  address = hostPortURL.Scheme + ":" + hostPortURL.Opaque } else { //否則為 http 協議  address = hostPortURL.Host  // 如果 host 不帶端口,則默認為 80  if strings.Index(hostPortURL.Host, ":") == -1 { //host 不帶端口, 默認 80   address = hostPortURL.Host + ":80"  } }
 //獲得了請求的 host 和 port,向服務端發起 tcp 連接 server, err := net.Dial("tcp", address) if err != nil {  log.Println(err)  return } //如果使用 https 協議,需先向客戶端表示連接建立完畢 if method == "CONNECT" {  fmt.Fprint(client, "HTTP/1.1 200 Connection established

") } else { //如果使用 http 協議,需將從客戶端得到的 http 請求轉發給服務端  server.Write(b[:n]) }
 //將客戶端的請求轉發至服務端,將服務端的響應轉發給客戶端。io.Copy 為阻塞函數,文件描述符不關閉就不停止 go io.Copy(server, client) io.Copy(client, server)}

		

添加代理,然后運行:

7ab1f91a-d2c2-11ec-bce3-dac502259ad0.png

7aeba5de-d2c2-11ec-bce3-dac502259ad0.png




原文標題:Golang 實現一個簡單的 http 代理

文章出處:【微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 服務器
    +關注

    關注

    12

    文章

    9303

    瀏覽量

    86060
  • HTTP
    +關注

    關注

    0

    文章

    511

    瀏覽量

    31518
  • 代理
    +關注

    關注

    1

    文章

    44

    瀏覽量

    11230

原文標題:Golang 實現一個簡單的 http 代理

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    內存管理概述及原理

    記錄一下,方便以后翻閱~主要內容:1) 內存管理概述及原理;2)相關實驗代碼解讀。官方資料:《STM32中文參考手冊_V10》-第19章 靈活的靜態存儲器控制器(FSMC)。實驗要求:系統啟動后
    發表于 02-23 06:15

    icepeak教程概述及工程應用

    icepeak教程概述及工程應用
    發表于 09-16 10:18 ?13次下載
    icepeak教程<b class='flag-5'>概述及</b>工程應用

    如何在java代碼中使用HTTP代理IP

    如何在java代碼中使用HTTP代理IP。
    的頭像 發表于 08-04 15:38 ?2274次閱讀

    python代碼中使用HTTP代理IP,demo注釋清晰

    如何再python代碼中使用HTTP代理IP。 以下代碼主要圍繞第一次接觸HTTP代理IP的py
    的頭像 發表于 08-04 15:40 ?1083次閱讀

    如何在python代碼中使用HTTP代理IP

    如何在python代碼中使用HTTP代理IP。
    的頭像 發表于 08-04 15:46 ?1317次閱讀

    如何在PHP代碼中使用HTTP代理IP

    如何在PHP代碼中使用HTTP代理IP。
    的頭像 發表于 08-04 16:08 ?2493次閱讀

    go語言代碼中使用HTTP代理IP的方法

    如何在go語言代碼中使用HTTP代理IP。
    的頭像 發表于 08-04 16:13 ?3239次閱讀

    如何在易e語言代碼中使用HTTP代理IP

    如何在易e語言代碼中使用HTTP代理IP,示例代碼demo直接可用(步驟注釋清晰)
    的頭像 發表于 08-05 16:29 ?7013次閱讀

    如何在c語言代碼中使用HTTP代理IP

    如何在c語言代碼中使用HTTP代理IP,示例代碼demo直接可用(步驟注釋清晰)
    的頭像 發表于 08-05 16:31 ?2395次閱讀

    如何在c#語言代碼中使用HTTP代理IP

    如何在c#語言代碼中使用HTTP代理IP,示例代碼demo直接可用(步驟注釋清晰)
    的頭像 發表于 08-05 16:33 ?2680次閱讀

    c語言中怎么使用HTTP代理

    如何再c語言代碼中使用HTTP代理IP。
    的頭像 發表于 09-01 14:44 ?1455次閱讀

    python代碼中如何使用HTTP代理

    華益云HTTP代理API有效期是一年,也就是說一年內這1萬IP用完就沒了,如果你一年都用不完那到時候剩余IP才會被清零,對于調試代碼來說時間充足靈活。
    的頭像 發表于 09-01 14:50 ?927次閱讀

    python代碼中如何使用HTTP代理

    HTTP代理就是介于瀏覽器和web服務器之間的一臺服務器,連接代理后,瀏覽器不再直接向web服務器取回網頁,而是向代理服務器發出request信號,
    的頭像 發表于 09-13 09:24 ?1324次閱讀

    如何在python代碼中使用HTTP代理IP

    如何再python代碼中使用HTTP代理IP。
    的頭像 發表于 09-13 09:25 ?1042次閱讀

    Golang實現一個簡單的http代理

    本文詳細介紹了Golang 實現 http 代理實現,在實際業務中有需求的同學可以學起來了!
    的頭像 發表于 04-10 11:29 ?1498次閱讀
    百家乐双筹码怎么出千| 老虎机破解| 百佬汇百家乐的玩法技巧和规则| 百家乐平注法到| 大发888娱乐代理| 百家乐开闲的几率多大| 德州扑克大小| 百家乐官网稳一点的押法| 3D乐财网| 百家乐官网游戏机博彩正网| 土豪百家乐官网的玩法技巧和规则 | 大发888娱乐城888bg| 百家乐官网分析下载| 澳门赌百家乐官网的玩法技巧和规则| 希尔顿百家乐试玩| 六合彩网站| 安桌百家乐官网游戏百家乐官网 | 申博百家乐公式软件| 赌场网站| 巴黎人百家乐官网的玩法技巧和规则| 玩百家乐输了| 府谷县| 回力百家乐官网的玩法技巧和规则| 威尼斯人娱乐场首页| 乐百家百家乐官网游戏| 大世界百家乐现金网| 顶级赌场代理| 百家乐官网网站制作| 免费百家乐追号| 杰克百家乐官网玩法| 发中发百家乐的玩法技巧和规则 | 百家乐发牌靴8| 百家乐官网前四手下注之观点| 百家乐平7s88| 淘金盈赌场有假吗| 大地百家乐官网的玩法技巧和规则| 澳门顶级赌场| 沙巴百家乐官网现金网| 爱赢百家乐开户送现金| 环球娱乐城| 百家乐美女视频|