一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

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

3天內(nèi)不再提示

Golang實現(xiàn)一個簡單的http代理

馬哥Linux運維 ? 來源:CSDN技術(shù)社區(qū) ? 2023-04-10 11:29 ? 次閱讀

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

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

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

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

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

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

正向代理:

http

https

socks4

socks5

vpn:就功能而言,vpn 也可以被認為是代理

反向代理:

tcp

udp

http

https

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

http 代理概述

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

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

http 協(xié)議

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

//直接連接
GET/HTTP/1.1
Host:staight.github.io
Connection:keep-alive

//http代理
GEThttp://staight.github.io/HTTP/1.1
Host:staight.github.io
Proxy-Connection:keep-alive

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

url 變成完整路徑,/->http://staight.github.io/

Connection字段變成Proxy-Connection字段

其余保持原樣

為什么使用完整路徑?

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

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

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

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

http 代理 http 協(xié)議交互過程如圖:

6306faa6-d6f2-11ed-bfe3-dac502259ad0.png

http 代理 http 協(xié)議

https 協(xié)議

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

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

如上,https 協(xié)議和 http 協(xié)議相比:

請求方法從GET變成CONNECT

url 沒有 protocol 字段

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

http 代理 https 協(xié)議交互過程如圖:

6314f73c-d6f2-11ed-bfe3-dac502259ad0.png

代碼實現(xiàn)

首先,創(chuàng)建 tcp 服務,并且對于每個 tcp 請求,均調(diào)用 handle 函數(shù):

//tcp連接,監(jiān)聽8080端口
l,err:=net.Listen("tcp",":8080")
iferr!=nil{
log.Panic(err)
}

//死循環(huán),每當遇到連接時,調(diào)用handle
for{
client,err:=l.Accept()
iferr!=nil{
log.Panic(err)
}

gohandle(client)
}

然后將獲取的數(shù)據(jù)放入緩沖區(qū):

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

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

varmethod,URL,addressstring
//從客戶端數(shù)據(jù)讀入method,url
fmt.Sscanf(string(b[:bytes.IndexByte(b[:],'
')]),"%s%s",&method,&URL)
hostPortURL,err:=url.Parse(URL)
iferr!=nil{
log.Println(err)
return
}

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

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

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

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

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

最后,將所有客戶端的請求轉(zhuǎn)發(fā)至服務端,將所有服務端的響應轉(zhuǎn)發(fā)給客戶端:

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

完整的源代碼:

packagemain

import(
"bytes"
"fmt"
"io"
"log"
"net"
"net/url"
"strings"
)

funcmain(){
//tcp連接,監(jiān)聽8080端口
l,err:=net.Listen("tcp",":8080")
iferr!=nil{
log.Panic(err)
}

//死循環(huán),每當遇到連接時,調(diào)用handle
for{
client,err:=l.Accept()
iferr!=nil{
log.Panic(err)
}

gohandle(client)
}
}

funchandle(clientnet.Conn){
ifclient==nil{
return
}
deferclient.Close()

log.Printf("remoteaddr:%v
",client.RemoteAddr())

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

varmethod,URL,addressstring
//從客戶端數(shù)據(jù)讀入method,url
fmt.Sscanf(string(b[:bytes.IndexByte(b[:],'
')]),"%s%s",&method,&URL)
hostPortURL,err:=url.Parse(URL)
iferr!=nil{
log.Println(err)
return
}

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

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

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

//將客戶端的請求轉(zhuǎn)發(fā)至服務端,將服務端的響應轉(zhuǎn)發(fā)給客戶端。io.Copy 為阻塞函數(shù),文件描述符不關(guān)閉就不停止
goio.Copy(server,client)
io.Copy(client,server)
}

添加代理,然后運行:

6321e8ac-d6f2-11ed-bfe3-dac502259ad0.png

632cae22-d6f2-11ed-bfe3-dac502259ad0.png

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Web
    Web
    +關(guān)注

    關(guān)注

    2

    文章

    1276

    瀏覽量

    70593
  • 服務器
    +關(guān)注

    關(guān)注

    12

    文章

    9596

    瀏覽量

    86986
  • 網(wǎng)絡
    +關(guān)注

    關(guān)注

    14

    文章

    7713

    瀏覽量

    90162
  • HTTP
    +關(guān)注

    關(guān)注

    0

    文章

    516

    瀏覽量

    32290
  • 客戶端
    +關(guān)注

    關(guān)注

    1

    文章

    296

    瀏覽量

    16940

原文標題:Golang 實現(xiàn)一個簡單的 http 代理

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

收藏 人收藏

    評論

    相關(guān)推薦

    Golang怎么實現(xiàn)UTS隔離

    Golang實現(xiàn)UTS隔離
    發(fā)表于 08-23 14:44

    http代理的分類

    有著不同的安全性,下面就隨著億牛云代理的腳步起看看HTTP代理是怎么按安全性分類的吧。透明代理(簡單
    發(fā)表于 12-20 17:25

    Golang爬蟲語言接入代理?

    都是可以寫出爬蟲系統(tǒng)的。無論用什么爬蟲語言框架,長期使用IP去采集數(shù)據(jù),肯定會收到限制。這種時候就需要使用爬蟲代理去解決問題。
    發(fā)表于 09-09 17:41

    HTTP反向代理服務器的編寫程序

    在 Node.js 上實現(xiàn)簡單HTTP 代理程序還是非常
    的頭像 發(fā)表于 10-06 10:00 ?4307次閱讀
    <b class='flag-5'>HTTP</b>反向<b class='flag-5'>代理</b>服務器的編寫程序

    如何在Golang實現(xiàn)反向代理

    【導讀】在本文中,我們將了解反向代理,它的應用場景以及如何在 Golang實現(xiàn)它。 反向代理是位于 Web 服務器前面并將客戶端(例如 Web 瀏覽器)的請求轉(zhuǎn)發(fā)到 Web 服務器
    的頭像 發(fā)表于 08-23 10:22 ?2293次閱讀

    http代理概述及代碼實現(xiàn)方法

    本文詳細介紹了Golang 實現(xiàn) http 代理實現(xiàn),在實際業(yè)務中有需求的同學可以學起來了!
    的頭像 發(fā)表于 05-14 15:02 ?4429次閱讀

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

    API鏈接,就可以跑起來了。 以下是示例代碼,只是基礎的演示,具體的代碼還是要根據(jù)你業(yè)務的實際情況去寫的。 示例代碼中的HTTP
    的頭像 發(fā)表于 08-04 15:40 ?1159次閱讀

    java中怎么使用HTTP代理

    java中怎么使用HTTP代理,華益云python爬蟲ip
    的頭像 發(fā)表于 09-01 14:31 ?1824次閱讀

    python中怎么使用HTTP代理

    python中怎么使用HTTP代理,華益云高匿爬蟲代理ip
    的頭像 發(fā)表于 09-01 14:36 ?1771次閱讀

    PHP中怎么使用HTTP代理

    PHP中怎么使用HTTP代理,華益云高匿爬蟲代理ip
    的頭像 發(fā)表于 09-01 14:38 ?1889次閱讀

    go語言中怎么使用HTTP代理

    go語言中怎么使用HTTP代理。
    的頭像 發(fā)表于 09-01 14:41 ?2568次閱讀

    http代理的作用如下所示

    經(jīng)常使用網(wǎng)絡的人可能會常常聽到這樣的一個詞:http代理。那么它真正的作用很多人都是模棱兩可的,在這里給大家普及下在我們大部分人的網(wǎng)絡活動中,ht
    發(fā)表于 09-15 13:00 ?564次閱讀

    解析Golang定時任務庫gron設計和原理

    正巧,最近看到了 gron 這個開源項目,它是用 Golang 實現(xiàn)并發(fā)安全的定時任務庫。實現(xiàn)非常
    的頭像 發(fā)表于 12-15 13:57 ?1528次閱讀

    快速應用程序開發(fā)(RAD)工具(Golang版)

    SNMPAgent Builder(Golang版)是快速應用程序開發(fā)(RAD)工具,用于基于Golang 的 SNMP代理開發(fā)。提供了
    的頭像 發(fā)表于 04-13 09:30 ?1720次閱讀

    Golang配置代理方法

    由于些客觀原因的存在,我們開發(fā) Golang 項目的過程總會碰到無法下載某些依賴包的問題。這不是小問題,因為你的工作會被打斷,即便你使用各種神通解決了問題,很可能這時你的線程已經(jīng)
    的頭像 發(fā)表于 11-11 11:17 ?842次閱讀
    <b class='flag-5'>Golang</b>配置<b class='flag-5'>代理</b>方法