目錄一、介紹二、安裝三、導入四、基本使用4.1 發送GET 請求4.2 POST請求發送JSON數據4.3 Post 文件上傳4.4 GoRequests 使用代理4.5 Gorequests 使用session五、HTTP服務端代碼 一、介紹 官方文檔 DOC: https://pkg.go.de ...
目錄
一、介紹
Python中的Requests
庫非常強大,所以Go開發者模仿Python的Requests
庫,由此誕生了Grequests
庫。Grequests
提供了一系列便利功能,使得發送HTTP請求變得簡單高效。下麵就是Grequests
在Golang中實現的一些關鍵特性:
- 響應序列化:
Grequests
支持將HTTP響應內容序列化為JSON和XML格式,讓處理API響應時更為方便。 - 文件上傳和下載:提供了便捷的方式來上傳和下載文件,無需複雜的配置。
- HTTP動詞支持:支持廣泛的HTTP動詞,包括GET、HEAD、POST、PUT、DELETE、PATCH以及OPTIONS,可以覆蓋大多數HTTP請求場景。
二、安裝
要開始使用Grequests庫,你需要先在你的Go環境中安裝它。通過下麵的命令即可完成安裝:
go get -u github.com/levigross/grequests
三、導入
在安裝完Grequests後,你可以通過import語句把它引入到你的Go代碼中:
import "github.com/levigross/grequests"
四、基本使用
4.1 發送GET 請求
下麵是一個發送GET請求的示例,其中演示瞭如何獲取HTTP響應並列印出來:
func Get() {
resp, err := grequests.Get("http://127.0.0.1:8080/book/", nil)
if err != nil {
log.Fatalln("Unable to make request: ", err)
}
if !resp.Ok {
log.Fatalln("請求超時!")
}
// 解析響應的JSON數據
var data []map[string]interface{}
if err := resp.JSON(&data); err != nil {
log.Fatalln("Unable to parse JSON response: ", err)
}
fmt.Println(data)
}
上面的代碼首先使用Get
方法發送GET請求,然後檢查是否有錯誤發生。如果沒有錯誤,就可以通過resp.Json()
方法獲取響應的文本內容。
4.2 POST請求發送JSON數據
在下麵的例子中,我們創建了一個map對象來保存我們想要發送的JSON數據。然後我們通過ROption
創建了一個請求選項對象,併在其中指定了JSON為發送的數據類型。最後,我們調用Post
方法來發送請求:
func Post() {
postData := map[string]string{
"id": "1",
"name": "Go入門到進階",
}
geq := &grequests.RequestOptions{
JSON: postData,
}
resp, err := grequests.Post("http://127.0.0.1:8080/book/create", geq)
if err != nil {
log.Fatalln("Unable to make request: ", err)
}
fmt.Println(resp.String())
}
下麵是代碼的逐行解釋:
postData := map[string]string{"id": "1", "name": "Go入門到進階"}
- 這裡定義了一個
map[string]string
類型的變數postData
,其中包含了兩個鍵值對,分別是"id"和"name",它們的值分別是"1"和"Go入門到進階"。
- 這裡定義了一個
geq := &grequests.RequestOptions{JSON: postData}
- 這裡創建了一個
grequests.RequestOptions
類型的變數geq
。grequests.RequestOptions
是一個結構體,用於配置HTTP請求的各種選項,如URL、方法、頭信息、數據等。在這個例子中,我們通過JSON
欄位將postData
作為JSON數據傳遞給POST請求。
- 這裡創建了一個
resp, err := grequests.Post("http://127.0.0.1:8080/book/create", geq)
- 這裡調用
grequests.Post
函數發起一個POST請求。http://127.0.0.1:8080/book/create
是請求的目標URL,而geq
是請求的配置選項。grequests.Post
函數會返回一個Response
對象和一個可能的錯誤。
- 這裡調用
if err != nil { log.Fatalln("Unable to make request: ", err) }
- 如果
grequests.Post
函數調用時發生錯誤,這個條件塊會執行。log.Fatalln
函數會列印錯誤消息並退出程式。
- 如果
fmt.Println(resp.String())
- 如果請求成功,這個條件塊會執行。
resp.String()
方法會返迴響應體的字元串表示,然後使用fmt.Println
函數將其列印到標準輸出。
總的來說,這段代碼的作用是向本地伺服器(假設在127.0.0.1:8080
上)的/book/create
路徑發送一個POST請求,請求體是JSON格式的數據,包含一個ID和書名。如果請求成功,它會列印出伺服器的響應。如果請求失敗,它會列印出錯誤信息並退出程式。
- 如果請求成功,這個條件塊會執行。
4.3 Post 文件上傳
文件上傳同樣簡單。你可以通過RequestOptions
指定文件:
func UploadFile() {
// 允許您通過指定磁碟上的位置來創建FileUpload結構片
// 打開要上傳的文件
file, err := os.Open("./go.mod")
if err != nil {
log.Fatalln("Unable to open file: ", err)
}
defer file.Close()
// 創建FileUpload結構片
ro := &grequests.RequestOptions{
Files: []grequests.FileUpload{{
FileName: "1.txt", // 上傳後的文件名稱
FieldName: "file", // 上傳文件對應欄位
FileContents: file, // 使用文件內容作為FileContents
}},
}
// 發送POST請求
resp, err := grequests.Post("http://127.0.0.1:8080/book/upload/", ro)
if err != nil {
log.Fatalln("Unable to make request: ", err)
}
fmt.Println(resp.String())
}
在上述代碼中,我們創建了一個FileUpload
結構,通過FileName
、FieldName
和FileContents
來指定我們要上傳的文件詳情。
4.4 GoRequests 使用代理
gorequest
代理,下麵是一個簡單的例子,需要把Proxies
中的URL添加為*url.URL
代理:
func Proxy() {
// 代理伺服器
const proxyServer = "http-pro.xxx.com:9010"
// 代理隧道驗證信息
const proxyUser = "xxxxxxxxx"
const proxyPass = "xxxxxxxxx"
// 初始化代理URL
proxyUrl, _ := url.Parse("http://" + proxyUser + ":" + proxyPass + "@" + proxyServer)
// 創建請求選項
ro := &grequests.RequestOptions{
Proxies: map[string]*url.URL{
"http": proxyUrl,
},
Headers: map[string]string{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
},
}
// 發起GET請求
resp, err := grequests.Get("http://www.example.com", ro)
if err != nil {
fmt.Println("Error:", err)
return
}
// 列印響應狀態碼
fmt.Println("Status code:", resp.StatusCode)
// 列印響應體
fmt.Println("Response:", resp.String())
}
下麵是代碼的逐行解釋:
// 代理伺服器
- 這一行是一個註釋,聲明瞭接下來的代碼將定義代理伺服器的URL。
const proxyServer = "http-pro.xxx.com:9010"
- 這裡定義了一個常量
proxyServer
,它的值是代理伺服器的URL,格式為http://host:port
。
- 這裡定義了一個常量
// 代理隧道驗證信息
- 這一行是一個註釋,聲明瞭接下來的代碼將定義代理隧道的驗證信息。
const proxyUser = "xxxxxxxxx"
- 這裡定義了一個常量
proxyUser
,它的值是代理隧道的用戶名。
- 這裡定義了一個常量
const proxyPass = "xxxxxxxxx"
- 這裡定義了一個常量
proxyPass
,它的值是代理隧道的密碼。
- 這裡定義了一個常量
// 初始化代理URL
- 這一行是一個註釋,說明接下來的代碼將創建代理URL。
proxyUrl, _ := url.Parse("http://" + proxyUser + ":" + proxyPass + "@" + proxyServer)
- 這行代碼使用
url.Parse
函數創建了一個代理URL。它將代理隧道的用戶名、密碼和代理伺服器地址組合成一個URL,格式為http://username:password@host:port
。_
是忽略返回值的約定,因為返回值通常不需要使用。
- 這行代碼使用
// 創建請求選項
- 這一行是一個註釋,說明接下來的代碼將創建一個
grequests.RequestOptions
結構體,用於配置HTTP請求。
- 這一行是一個註釋,說明接下來的代碼將創建一個
ro := &grequests.RequestOptions{
- 這裡開始定義
grequests.RequestOptions
結構體變數ro
。
- 這裡開始定義
Proxies: map[string]*url.URL{
- 這裡定義了
Proxies
欄位,它是一個映射,將協議(如"http")映射到代理URL。
- 這裡定義了
"http": proxyUrl,
- 這行代碼將代理URL設置為HTTP協議的代理。
},
- 這是映射定義的結束。
Headers: map[string]string{
- 這裡定義了
Headers
欄位,它是一個映射,將HTTP頭欄位(如"user-agent")映射到相應的值。
- 這裡定義了
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
- 這行代碼設置了一個HTTP頭欄位,即用戶代理(User-Agent),用於標識發起請求的客戶端。
},
- 這是映射定義的結束。
}
- 這是
grequests.RequestOptions
結構體變數的定義結束。
- 這是
// 發起GET請求
- 這一行是一個註釋,說明接下來的代碼將發起一個GET請求。
resp, err := grequests.Get("http://www.example.com", ro)
- 這行代碼使用
grequests.Get
函數發起一個GET請求。http://www.example.com
是請求的目標URL,而ro
是請求的配置選項。grequests.Get
函數會返回一個Response
對象和一個可能的錯誤。
- 這行代碼使用
if err != nil {
- 如果
grequests.Get
函數調用時發生錯誤,這個條件塊會執行。
- 如果
fmt.Println("Error:", err)
- 這行代碼列印出錯誤信息。
return
- 這行代碼表示如果發生錯誤,函數將返回,不繼續執行。
}
- 這是錯誤處理塊的結束。
fmt.Println("Status code:", resp.StatusCode)
- 如果請求成功,這行代碼會列印出響應的狀態碼。
fmt.Println("Response:", resp.String())
4.5 Gorequests 使用session
下麵是使用Session的一個例子:
session := grequests.Session{
RequestOptions: &grequests.RequestOptions{
Headers: map[string]string{
"authority": "mp3.haoge500.com",
"referer": "https://www.zz123.com/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
},
},
}
五、HTTP服務端代碼
package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
"net/http"
"os"
)
type Book struct {
ID string `json:"id"`
Name string `json:"name"`
}
type BookHandler struct {
}
func (b *BookHandler) RegisterRoutes(server *gin.Engine) {
bg := server.Group("/book")
bg.POST("/upload", b.Upload)
bg.POST("/create", b.Create)
bg.GET("/", b.GetAllBooks) // 查詢書籍
}
func (b *BookHandler) Upload(ctx *gin.Context) {
// 從請求中獲取文件
file, err := ctx.FormFile("file")
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "無法獲取上傳的文件"})
return
}
// 將文件保存到伺服器
// 註意:這裡需要確保保存文件的目錄存在,並且伺服器有寫入許可權
savePath := "./uploads/" + file.Filename
if err := ctx.SaveUploadedFile(file, savePath); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "文件保存失敗"})
return
}
ctx.JSON(http.StatusOK, gin.H{"message": "文件上傳成功"})
}
func (b *BookHandler) Create(ctx *gin.Context) {
var req Book
if err := ctx.Bind(&req); err != nil {
return
}
// 將新的書籍數據保存到data.json文件中
if err := addBookToFile(&req); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save book data"})
return
}
ctx.JSON(http.StatusOK, gin.H{"message": "Book added successfully"})
}
func (b *BookHandler) GetAllBooks(c *gin.Context) {
// 從data.json文件中讀取書籍數據
books, err := getBooksFromFile()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read book data"})
return
}
// 獲取URL查詢參數中的id
id := c.Query("id")
// 如果提供了ID,查找具有匹配ID的書籍列表
if id != "" {
// 查找具有匹配ID的書籍
var foundBooks []Book
for _, book := range books {
if book.ID == id {
foundBooks = append(foundBooks, book)
}
}
// 如果找到了匹配的書籍,返回這些書籍
if len(foundBooks) > 0 {
c.JSON(http.StatusOK, foundBooks)
return
}
// 如果沒有找到匹配的書籍,返回404
c.JSON(http.StatusNotFound, gin.H{"error": "Books not found"})
return
}
// 如果沒有提供ID,返回所有書籍
c.JSON(http.StatusOK, books)
}
func addBookToFile(book *Book) error {
// 讀取現有的data.json文件內容
var books []Book
data, err := os.ReadFile("data.json")
if err != nil && !os.IsNotExist(err) {
return err
}
// 如果文件存在,解析現有的書籍數據
if err == nil {
if err := json.Unmarshal(data, &books); err != nil {
return err
}
}
// 將新的書籍添加到數組中
books = append(books, *book)
// 將更新後的書籍數組序列化為JSON
newData, err := json.MarshalIndent(books, "", " ")
if err != nil {
return err
}
// 將序列化的JSON數據寫入data.json文件
if err := os.WriteFile("data.json", newData, 0644); err != nil {
return err
}
return nil
}
func getBooksFromFile() ([]Book, error) {
// 讀取data.json文件內容
data, err := os.ReadFile("data.json")
if err != nil {
return nil, err
}
// 解析JSON數據到書籍數組中
var books []Book
if err := json.Unmarshal(data, &books); err != nil {
return nil, err
}
return books, nil
}
func InitWebServer(bookHandler *BookHandler) *gin.Engine {
server := gin.Default()
bookHandler.RegisterRoutes(server)
return server
}
func main() {
// 確保上傳目錄存在
os.MkdirAll("./uploads", 0755)
bookHandler := &BookHandler{}
server := InitWebServer(bookHandler)
server.Run(":8080") // 在8080埠啟動伺服器
}
分享是一種快樂,開心是一種態度!