成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Golang 實現一個簡單的 http 代理

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

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

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

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

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

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

  •  正向代理:
    •  http
    •  https
    •  socks4
    •  socks5
  •  反向代理:
    •  tcp
    •  udp
    •  http
    •  https

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

http 代理概述

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

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

http 協議

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

  1. // 直接連接  
  2. GET / HTTP/1.1  
  3. Host: staight.github.io  
  4. Connection: keep-alive  
  5. // http 代理  
  6. GET http://staight.github.io/ HTTP/1.1  
  7. Host: staight.github.io  
  8. Proxy-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 協議交互過程如圖:

http 代理 http 協議

https 協議

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

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

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

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

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

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

http 代理 https 協議

代碼實現

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

  1. // tcp 連接,監聽 8080 端口  
  2. l, err :net.Listen("tcp", ":8080")  
  3. if err != nil {  
  4.  log.Panic(err)  
  5.  
  6. // 死循環,每當遇到連接時,調用 handle  
  7. for {  
  8.  client, err :l.Accept()  
  9.  if err != nil {  
  10.   log.Panic(err)  
  11.  }   
  12.  go handle(client)  
  13.    }  
  14. 然后將獲取的數據放入緩沖區:  
  15. // 用來存放客戶端數據的緩沖區  
  16. var b [1024]byte  
  17. //從客戶端獲取數據  
  18. n, err :client.Read(b[:])  
  19. if err != nil {  
  20.  log.Println(err)  
  21.  return  
  22.    } 

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

  1. var method, URL, address string  
  2. // 從客戶端數據讀入 method,url  
  3. fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &URL)  
  4. hostPortURL, err :url.Parse(URL)  
  5. if err != nil { 
  6.  log.Println(err) 
  7.   return  
  8.    } 

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

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

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

  1. //獲得了請求的 host 和 port,向服務端發起 tcp 連接  
  2. server, err :net.Dial("tcp", address)  
  3. if err != nil {  
  4.  log.Println(err)  
  5.  return  
  6.  
  7. //如果使用 https 協議,需先向客戶端表示連接建立完畢  
  8. if method == "CONNECT" {  
  9.  fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n")  
  10. } else { //如果使用 http 協議,需將從客戶端得到的 http 請求轉發給服務端  
  11.  server.Write(b[:n])  
  12.    } 

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

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

完整的源代碼: 

  1. package main  
  2. import (  
  3.  "bytes"  
  4.  "fmt"  
  5.  "io"  
  6.  "log"  
  7.  "net"  
  8.  "net/url"  
  9.  "strings"  
  10.   
  11. func main() {  
  12.  // tcp 連接,監聽 8080 端口  
  13.  l, err :net.Listen("tcp", ":8080")  
  14.  if err != nil {  
  15.   log.Panic(err)  
  16.  }   
  17.  // 死循環,每當遇到連接時,調用 handle  
  18.  for {  
  19.   client, err :l.Accept()  
  20.   if err != nil {  
  21.    log.Panic(err)  
  22.   }  
  23.   go handle(client)  
  24.  }  
  25.  
  26. func handle(client net.Conn) { 
  27.  if client == nil {  
  28.   return  
  29.  }  
  30.  defer client.Close()  
  31.  log.Printf("remote addr: %v\n", client.RemoteAddr())  
  32.  // 用來存放客戶端數據的緩沖區  
  33.  var b [1024]byte  
  34.  //從客戶端獲取數據  
  35.  n, err :client.Read(b[:])  
  36.  if err != nil {  
  37.   log.Println(err)  
  38.   return 
  39.   
  40.  var method, URL, address string  
  41.  // 從客戶端數據讀入 method,url  
  42.  fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &URL)  
  43.  hostPortURL, err :url.Parse(URL)  
  44.  if err != nil {  
  45.   log.Println(err)  
  46.   return  
  47.  }  
  48.  // 如果方法是 CONNECT,則為 https 協議  
  49.  if method == "CONNECT" {  
  50.   address = hostPortURL.Scheme + ":" + hostPortURL.Opaque  
  51.  } else { //否則為 http 協議  
  52.   address = hostPortURL.Host  
  53.   // 如果 host 不帶端口,則默認為 80  
  54.   if strings.Index(hostPortURL.Host, ":") == -1 { //host 不帶端口, 默認 80  
  55.    address = hostPortURL.Host + ":80"  
  56.   }  
  57.  }  
  58.  //獲得了請求的 host 和 port,向服務端發起 tcp 連接  
  59.  server, err :net.Dial("tcp", address)  
  60.  if err != nil {  
  61.   log.Println(err)  
  62.   return  
  63.  }  
  64.  //如果使用 https 協議,需先向客戶端表示連接建立完畢  
  65.  if method == "CONNECT" {  
  66.   fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n")  
  67.  } else { //如果使用 http 協議,需將從客戶端得到的 http 請求轉發給服務端  
  68.   server.Write(b[:n])  
  69.  }  
  70.  //將客戶端的請求轉發至服務端,將服務端的響應轉發給客戶端。io.Copy 為阻塞函數,文件描述符不關閉就不停止  
  71.  go io.Copy(server, client)  
  72.  io.Copy(client, server)  

添加代理,然后運行:

添加代理

運行 

 

責任編輯:龐桂玉 來源: 馬哥Linux運維
相關推薦

2021-12-14 09:00:42

Swift HTTP 代理服務器

2024-01-08 08:36:29

HTTPGo代理服務器

2015-12-02 14:10:56

HTTP網絡協議代理原理

2018-09-18 10:11:21

前端vue.jsjavascript

2016-11-08 18:53:08

編譯器

2022-09-08 06:23:37

C++HTTP 服務器

2022-11-29 17:34:43

虛擬形象系統

2017-12-27 09:49:35

HTTP服務器反向

2020-06-04 12:55:44

PyTorch分類器神經網絡

2024-05-07 09:02:47

2019-04-24 15:06:37

Http服務器協議

2021-05-20 07:56:35

Bean容器Spring

2019-12-11 10:45:08

Python 開發編程語言

2011-03-24 09:34:41

SPRING

2015-12-02 15:29:32

HTTP網絡協議代理原理

2024-04-26 09:04:13

2022-04-08 08:26:03

JavaHTTP請求

2022-09-19 08:01:45

數據庫SQLitePostgreSQL

2022-10-21 14:21:46

JavaScript筆記技能

2022-12-29 12:06:28

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久久久亚洲 | 91国产精品 | 亚洲成人在线免费 | 夜夜av | 欧美中国少妇xxx性高请视频 | 中文字幕国产视频 | 免费午夜电影 | 天天看天天爽 | 久久久999成人 | 久久美国| 久久久久久久久99 | 91精品国产91久久久久久最新 | 免费一区 | 亚洲成人三区 | 懂色tv| 亚洲天堂影院 | 激情欧美一区二区三区中文字幕 | 日本久久精品 | 婷婷色综合 | 成人高清视频在线观看 | 国产精品久久久久久久久久东京 | 国产精品成人久久久久a级 久久蜜桃av一区二区天堂 | 91精品久久久久久久久久入口 | 成人午夜免费福利视频 | 丁香五月网久久综合 | 在线看av网址 | 中文字幕免费视频 | 国产真实精品久久二三区 | 欧美日韩高清免费 | 夜夜干夜夜操 | 欧美亚州综合 | 精品久久香蕉国产线看观看亚洲 | 午夜爽爽爽男女免费观看 | av性色| 在线一区视频 | 精品成人佐山爱一区二区 | 日韩成人高清在线 | 超碰97人人人人人蜜桃 | 国产欧美精品一区 | 久久精品成人 | 99国产欧美 |