Go 標準庫之 GoRequests 介紹與基本使用

来源:https://www.cnblogs.com/taoxiaoxin/p/18136833
-Advertisement-
Play Games

目錄一、介紹二、安裝三、導入四、基本使用4.1 發送GET 請求4.2 POST請求發送JSON數據4.3 Post 文件上傳4.4 GoRequests 使用代理4.5 Gorequests 使用session五、HTTP服務端代碼 一、介紹 官方文檔 DOC: https://pkg.go.de ...


目錄

一、介紹

官方文檔 DOC: https://pkg.go.dev/github.com/levigross/grequests

Github: http://github.com/levigross/grequests

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())
}

下麵是代碼的逐行解釋:

  1. postData := map[string]string{"id": "1", "name": "Go入門到進階"}
    • 這裡定義了一個map[string]string類型的變數postData,其中包含了兩個鍵值對,分別是"id"和"name",它們的值分別是"1"和"Go入門到進階"。
  2. geq := &grequests.RequestOptions{JSON: postData}
    • 這裡創建了一個grequests.RequestOptions類型的變數geqgrequests.RequestOptions是一個結構體,用於配置HTTP請求的各種選項,如URL、方法、頭信息、數據等。在這個例子中,我們通過JSON欄位將postData作為JSON數據傳遞給POST請求。
  3. 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對象和一個可能的錯誤。
  4. if err != nil { log.Fatalln("Unable to make request: ", err) }
    • 如果grequests.Post函數調用時發生錯誤,這個條件塊會執行。log.Fatalln函數會列印錯誤消息並退出程式。
  5. 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結構,通過FileNameFieldNameFileContents來指定我們要上傳的文件詳情。

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())
}

下麵是代碼的逐行解釋:

  1. // 代理伺服器
    • 這一行是一個註釋,聲明瞭接下來的代碼將定義代理伺服器的URL。
  2. const proxyServer = "http-pro.xxx.com:9010"
    • 這裡定義了一個常量proxyServer,它的值是代理伺服器的URL,格式為http://host:port
  3. // 代理隧道驗證信息
    • 這一行是一個註釋,聲明瞭接下來的代碼將定義代理隧道的驗證信息。
  4. const proxyUser = "xxxxxxxxx"
    • 這裡定義了一個常量proxyUser,它的值是代理隧道的用戶名。
  5. const proxyPass = "xxxxxxxxx"
    • 這裡定義了一個常量proxyPass,它的值是代理隧道的密碼。
  6. // 初始化代理URL
    • 這一行是一個註釋,說明接下來的代碼將創建代理URL。
  7. proxyUrl, _ := url.Parse("http://" + proxyUser + ":" + proxyPass + "@" + proxyServer)
    • 這行代碼使用url.Parse函數創建了一個代理URL。它將代理隧道的用戶名、密碼和代理伺服器地址組合成一個URL,格式為http://username:password@host:port_是忽略返回值的約定,因為返回值通常不需要使用。
  8. // 創建請求選項
    • 這一行是一個註釋,說明接下來的代碼將創建一個grequests.RequestOptions結構體,用於配置HTTP請求。
  9. ro := &grequests.RequestOptions{
    • 這裡開始定義grequests.RequestOptions結構體變數ro
  10. Proxies: map[string]*url.URL{
    • 這裡定義了Proxies欄位,它是一個映射,將協議(如"http")映射到代理URL。
  11. "http": proxyUrl,
    • 這行代碼將代理URL設置為HTTP協議的代理。
  12. },
    • 這是映射定義的結束。
  13. Headers: map[string]string{
    • 這裡定義了Headers欄位,它是一個映射,將HTTP頭欄位(如"user-agent")映射到相應的值。
  14. "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),用於標識發起請求的客戶端。
  15. },
    • 這是映射定義的結束。
  16. }
    • 這是grequests.RequestOptions結構體變數的定義結束。
  17. // 發起GET請求
    • 這一行是一個註釋,說明接下來的代碼將發起一個GET請求。
  18. resp, err := grequests.Get("http://www.example.com", ro)
    • 這行代碼使用grequests.Get函數發起一個GET請求。http://www.example.com是請求的目標URL,而ro是請求的配置選項。grequests.Get函數會返回一個Response對象和一個可能的錯誤。
  19. if err != nil {
    • 如果grequests.Get函數調用時發生錯誤,這個條件塊會執行。
  20. fmt.Println("Error:", err)
    • 這行代碼列印出錯誤信息。
  21. return
    • 這行代碼表示如果發生錯誤,函數將返回,不繼續執行。
  22. }
    • 這是錯誤處理塊的結束。
  23. fmt.Println("Status code:", resp.StatusCode)
    • 如果請求成功,這行代碼會列印出響應的狀態碼。
  24. 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埠啟動伺服器
}

分享是一種快樂,開心是一種態度!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、首先構造函數為中心 function Person() { } var p = new Person(); console.log('Person::', p) console.log(p.constructor Person) 列印如下: 可以看出構造函數通過new得到實例,實例可以通過【co ...
  • 今天我為大家帶來新的作品,iOS17桌面組件神器(Scriptable)原創腳本,精美作品分享!喜歡的話就點關註吧!更多腳本正在路上... * script : ONE-Progress.js * version : 1.0.0 * author : Nicolas-kings * date : 2 ...
  • 適配器模式(Adapter Pattern) 結構型設計模式,見名知意,就是兩個不相容的介面之間的橋梁。它結合了兩個獨立介面的功能。 主要解決:常常要將一些"現存的對象"放到新的環境中,而新環境要求的介面是現對象不能滿足的。 關鍵代碼:適配器繼承或依賴已有的對象,實現想要的目標介面。 優點: 1、可 ...
  • 領域驅動設計(DDD)裡面有一堆專業術語,比如領域、子域、核心域、通用域、支撐域等等,聽著是不是覺得挺嚇人?別怕,我來帶你輕鬆搞懂它們。 如何理解領域和子域? 領域是指一定的業務範圍或問題域。在解決業務問題時,DDD 會將業務領域進行細分,將問題範圍限定在一定的邊界內,在這個邊界內建立領域模型,用代 ...
  • 策略模式(Strategy Pattern) 指對象有某個行為,但是在不同的場景中,該行為有不同的實現演算法。將每個演算法封裝在獨立的類中,使得它們可以互相替換。可以在運行時根據需要選擇不同的演算法,而不需要修改客戶端代碼。 主要解決:在有多種演算法相似的情況下,使用 if...else 所帶來的複雜和難以 ...
  • 抽象工廠模式(Abstract Factory Pattern): 是圍繞一個超級工廠創建其他工廠。該超級工廠又稱為其他工廠的工廠。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。 在抽象工廠模式中,介面是負責創建一個相關對象的工廠,不需要顯式指定它們的類。每個生成的工廠都能按照工 ...
  • 原理 在看雪看到一篇文章:逆向調用QQ截圖NT與WeChatOCR-軟體逆向。裡面說了怎麼調用微信和QQ本地的OCR模型,還有很詳細的分析過程。 我稍微看了下文章,多的也看不懂。大概流程是使用mmmojo.dll這個dll來與WeChatOCR.exe做通信的,也是用它來啟動和關閉WeChatOCR ...
  • C++ 預設參數 預設參數概述 在 C++ 中,函數參數可以擁有預設值。這意味著,在調用函數時,如果省略了某個參數,那麼將使用為該參數指定的預設值。 設置預設參數 預設參數值使用等號 = 符號進行設置,位於參數聲明的類型之後。例如: void myFunction(string country = ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...