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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...