Go语言Http调用之Get、Post请求详解

HTTP 调用需要通过 http 包里的 Client 结构体里的 Do 方法去实现,因此需要先声明一个 Client 结构体变量,该结构体可以设置超时时间等配置。 对于一个请求里的 URL,查询参数,请求 method 等参数,需要 http 包里的 Request 结构体去封装。我们可以通过 NewRequestWithContext 或 NewRequest 函数获取一个基础的 Request 结构体指针变量。 NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error) 参数 ctx 为 Context 的接口类型,任意实现 Context 接口的自定义类型都可以作为此参数传递。 参数 method 为 HTTP 方法参数,可选值有 GET、POST、DELETE、PUT等。 参数 url 为接口的请求路径。 参数 body,为请求体参数。 通过 client.Do(req) 方法调用之后,返回值有 (*Response, error),第一个是响应结构体参数,第二个是错误参数。通过读取 Response 的 body 的值,可以获取接口的响应体。 一、GET import ( "context" "fmt" "io" "net/http" ) func main() { client := http.Client{} request, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://localhost:8080/user?name=tom", nil) if err != nil { return } request.Header.Set("headerParam", "header") resp, err := client.Do(request) if err != nil { fmt.Println(err) return } bytes, err := io.ReadAll(resp.Body) if err != nil { return } defer resp.Body.Close() fmt.Println(string(bytes)) // {"code":0,"data":{"list":},"message":"success"} } 需要携带查询参数时,可以直接拼接在 url 字符串上面。 header 参数可以通过 request 结构体的 Header 字段的 set 方法或 add 方法进行设置。 HTTP 请求响应码可以通过 Response 的 StatusCode 字段进行查看。 接口请求成功之后,通过 io.ReadAll 方法,读取 resp.Body 响应体信息。 除了直接在 url 上拼接 query 参数的方式,我们还可以通过以下方式进行添加 query 参数: params := url.Values{} rawUrl, err := url.Parse("http://localhost:8080/user") if err != nil { return } params.Set("name", "tom") rawUrl.RawQuery = params.Encode() u := rawUrl.String() 通过 url.Values 结构体的 set 方法设置 query参数,url 通过 url.Parse 函数生成一个 URL 结构体指针变量,rawUrl.RawQuery = params.Encode() 通过这行代码将 query 参数和 url 进行绑定,最后通过 String() 方法将 url 转换成 string 类型。 二、POST 发起 HTTP POST

Go 的时间格式化为什么是 2006-01-02 15:04:05?

go语言中有个很特别的时间格式format,在我们使用 Format格式化时间的时候, format的参数格式字符串必须是 2006-01-02 15:04:05 才能格式出正确的时间来, 这是个很特别的字符串, 通过分析拆分后可以得出的每个代表时间和日期的数字都不重复。 这里的 2006-01-02 15:04:05 这里的数字可以对年月日时分秒分别拆分为一个独立的数字格式, 可以看出拆分后的数字都是独立的 都分别代表对应位置的日期,如 2006表示4位年份, 06表示2位年份, 01表示2位月份,1表示不带0的月份, 02表示2位日期,2表示不带0的日期, 15表示小时, 04表示分钟,4表示不带0的分钟, 05表示秒, 5表示不带0的秒等 go time日期时间格式实例: package main import ( "fmt" "time" ) func main() { // 获取当前时间 now := time.Now() // time.Now()返回的类型是 time.Time 详情参考 ~/.gvm/go/src/time/time.go fmt.Printf("%d-%d-%d %d:%d:%d\n", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) // 2024-5-5 10:41:37 // 注意这里的Format() // func (t time.Time) Format(layout string) string // 这里的layout必须是这个时间 2006-01-02 15:04:05 其组合格式可以修改,但是数字不可修改 fmt.Printf("%v\n", now.Format("2006-01-02 15:04:05")) // 为什么是这个时间(2006-01-02 15:04:05),据说这个时间是go语言想法诞生的时间 // 2024-05-05 10:45:39 fmt.Printf("%v\n", now.Format("06")) // 年份: 06表示2位年份 如:24, 2006表示4位年份,如 2024 fmt.Printf("%v\n", now.Format("1")) // 当前月份: 1表示 1-12, 如果是01表示 01-12 fmt.Printf("%v\n", now.Format("05")) // 当前秒: 05表示 01-59 , 如果是5则表示秒 1-59 } 为什么这样设计? 实际上 2006-01-02 15:04:05 是一个参考时间的格式,也就是其它语言中 Y-m-d H:i:s 格式,在功能上用于时间的格式化处理和规范。 那为什么是 2006-01-02 15:04:05 呢?其实这些 ”数字“ 是有意义的,每个布局字符串都是一个时间戳的表示,并非随便写的时间点。 Jan 2 15:04:05 2006 MST 1 2 3 4 5 6 -7 我们也可以将其记忆为 2006 年 1 月 2 日 3 点 4 分 5 秒。 不方便记,go将会在 Go1.20 增加如下三个常量: DateTime = "2006-01-02 15:04:05" DateOnly = "2006-01-02" TimeOnly = "15:04:05"

beego开启CORS

问题 要在Beego中开启CORS,需要使用插件cors,并针对不同的路由类型进行设置。 示例 普通路由 beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{ AllowOrigins: string{"*"}, //AllowMethods: string{"POST", "GET", "OPTIONS"}, //AllowHeaders: string{"Origin"}, //ExposeHeaders: string{"Content-Length"}, //AllowCredentials: true, })) 静态文件路由 beego.InsertFilter("*", beego.BeforeStatic, cors.Allow(&cors.Options{ AllowOrigins: string{"*"}, //AllowMethods: string{"POST", "GET", "OPTIONS"}, //AllowHeaders: string{"Origin"}, //ExposeHeaders: string{"Content-Length"}, //AllowCredentials: true, }))

go操作aws s3

v2 官方推荐版本,需要go版本>=1.20 安装 go get github.com/aws/aws-sdk-go-v2 go get github.com/aws/aws-sdk-go-v2/config go get github.com/aws/aws-sdk-go-v2/service/s3 必要参数 bucket: 存储桶的名称 Region: 存储桶所在区域,例us-east-1 accessKeyID: 访问存储桶所需的KeyID secretAccessKey: 访问存储桶所需的AccessKey 如何获取accessKeyID和secretAccessKey:指南 var ( s3Client *s3.Client bucket = "yourbucketname" ) func InitS3Client() { accessKeyID := "xxxxx" secretAccessKey := "xxxxx" cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("ap-east-1"), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")), ) if err != nil { log.Fatalf("unable to load SDK config, %v", err) } s3Client = s3.NewFromConfig(cfg) } func UploadToS3(filePath, fileName, mimeType string) (string, error) { file, err := os.Open(filePath) if err != nil { return "", fmt.Errorf("failed to open file %q, %v", filePath, err) } defer file.Close() _, err = s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String(bucket), Key: aws.String(fileName), Body: file, ContentType: aws.String(mimeType), }) if err != nil { return "", fmt.Errorf("failed to upload file to S3, %v", err) } return fmt.Sprintf("https://%s.s3.amazonaws.com/%s", bucket, fileName), nil } 参考2 // 创建s3Client实例。 payKeyId := "AK***" paySecret := "oiy***" accessKeyID := payKeyId secretAccessKey := paySecret cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion("ap-east-1"), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")), ) if err != nil { fmt.Printf("unable to load SDK config, %v", err) } name := "test" s3Client := s3.NewFromConfig(cfg) filePath := "static/test.jpg" // 读取本地文件。 fd, err := os.Open(filePath) if err != nil { return } defer fd.Close() _, err = s3Client.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String("up"), Key:

golang jwt 签署令牌Authentication token

1.要安装 jwt 包,首先需要 安装Go,然后可以使用下面的命令将其添加jwt-go为 Go 程序中的依赖项。 go get -u github.com/golang-jwt/jwt/v5 2.将其导入到您的代码中: import "github.com/golang-jwt/jwt/v5" 3.demo func Test(t *testing.T) { //商户 subject := "01H" // 密钥 secretBase64 := "AwFj+OTCI=" secret, err := base64.StdEncoding.DecodeString(secretBase64) if err != nil { log.Fatalf("Error decoding base64 secret: %v", err) } // 过期秒数 expirseIn := 60 * time.Second // 创建jwt token token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "sub": subject, "exp": time.Now().Add(expirseIn).Unix(), }) // 使用密钥签名 tokenString, err := token.SignedString(secret) if err != nil { log.Fatalf("Error signing token: %v", err) } fmt.Println("tokenString=", tokenString) m := make(mapinterface m = "www" m = "qqq" // 将数据转为JSON格式 jsonData, err := json.Marshal(m) if err != nil { log.Fatalf("Error marshalling JSON: %v", err) } client := &http.Client{} url := "https://demo.com" method := "POST" req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonData)) if err != nil { log.Fatalf("Error creating request: %v", err) } req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", tokenString)) req.Header.Set("Content-Type", "application/json; charset=utf-8") resp, err := client.Do(req) if err != nil { log.Fatalf("Error sending request: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatalf("Error reading response body: %v", err) } log.Printf("Response body: %s", string(body)) } log.Printf("Response StatusCode: %d,%d", resp.StatusCode,http.StatusOK) info := TestRespone{} err = ffjson.Unmarshal(body, &info) if err != nil { log.Printf("body

gin获取请求体(json格式)参数

gin 框架里 c.PostForm() 函数只能从表单中获取参数,不能从 body 中解析表单参数,也就是说你如果用 c.PostForm() 来解析获取参数,客户端发起请求时,如果参数放在表单(form-data)里,服务端能正常获取到参数,但是如果客户端把参数放在 raw 里,即使 header 里配置了 content-type:multipart/form-data,服务端仍就无法获取到参数。 c.PostForm获取表单数据 package main import ( "bytes" "fmt" "github.com/gin-gonic/gin" "io/ioutil" ) func main() { gin.SetMode(gin.ReleaseMode) r := gin.Default() r.GET("/test", func(c *gin.Context) { data, _ := ioutil.ReadAll(c.Request.Body) fmt.Printf("req.body=%s\n, content-type=%v\n", data, c.ContentType()) // 这点很重要,把字节流重新放回 body 中 c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) // 获取参数 userName := c.PostForm("user_name") age := c.PostForm("age") fmt.Printf("userName=%s, age=%s\n", userName, age) c.JSON(200, "success") }) r.Run(":7000") } 或 func Test(c *gin.Context) error { m := make(mapinterface{}) m = c.Request.PostFormValue("memberid") // 商户ID m = c.Request.PostFormValue("orderid") // 订单号 } 从body中获取参数 package main import ( "bytes" "encoding/json" "fmt" "github.com/gin-gonic/gin" "io" "io/ioutil" ) type User struct { UserName string `json:"user_name"` Age int `json:"age"` } // 关键 func JSONDecode(r io.Reader, obj interface{}) error { if err := json.NewDecoder(r).Decode(obj); err != nil { return err } return nil } func main() { gin.SetMode(gin.ReleaseMode) r := gin.Default() r.POST("/test", func(c *gin.Context) { // 打印出 body //data, _ := ioutil.ReadAll(c.Request.Body) //fmt.Printf("req.body=%s\n, content-type=%v\n", data, c.ContentType()) var json User data, err := c.GetRawData() if err != nil { fmt.Println(err.Error()) } fmt.Println("data:", string(data)) // 把字节流重新放回 body 中 c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) err2 := JSONDecode(c.Request.Body, &json) if err2 != nil { fmt.Println("decode err:", err2) } // 打印body中的参数 fmt.Println("user_name:", json.UserName, "age:", json.Age) c.JSON(200, "success") }) r.Run(":7000")

golang 使用 gomail 发送邮件

安装gomail go get gopkg.in/gomail.v2 package main import ( "crypto/tls" "fmt" "gopkg.in/gomail.v2" ) func main() { test1() } func test1() { message := ` <p> Hello %s,</p> <p style="text-indent:2em">测试测试测试测试.</p> <p style="text-indent:2em">测试11111</p> ` // QQ 邮箱: // SMTP 服务器地址:smtp.qq.com(SSL协议端口:465/994 | 非SSL协议端口:25) // 163 邮箱: // SMTP 服务器地址:smtp.163.com(端口:25) host := "xxxxx" port := 25 userName := "xxxx" // 有些油箱登入名不是邮箱地址 password := "xxxx" fromemail := "xx@xx.com" m := gomail.NewMessage() m.SetHeader("From", fromemail) // 发件人 // m.SetHeader("From", "alias"+"<"+userName+">") // 增加发件人别名 // 多个收件人形式 // mailTo := string{ // "******@qq.com", // "******@qq.com", // } // m.SetHeader("To", mailTo...) m.SetHeader("To", "xxxxx@qq.com") // 收件人,可以多个收件人,但必须使用相同的 SMTP 连接 // 多个同上 // m.SetHeader("Cc", "******@qq.com") // 抄送,可以多个 // m.SetHeader("Bcc", "******@qq.com") // 暗送,可以多个 m.SetHeader("Subject", "发送测试11111") // 邮件主题 // text/html 的意思是将文件的 content-type 设置为 text/html 的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。 // 可以通过 text/html 处理文本格式进行特殊处理,如换行、缩进、加粗等等 m.SetBody("text/html", fmt.Sprintf(message, "测试")) // text/plain的意思是将文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理 // m.SetBody("text/plain", "纯文本") // m.Attach("test.sh") // 附件文件,可以是文件,照片,视频等等 // m.Attach("lolcatVideo.mp4") // 视频 // m.Attach("lolcat.jpg") // 照片 d := gomail.NewDialer( host, port, userName, password, ) // 关闭SSL协议认证 d.TLSConfig = &tls.Config{InsecureSkipVerify: true} if err := d.DialAndSend(m); err != nil { panic(err) } } package main import ( "gopkg.in/gomail.v2" "strconv" ) func SendMail(mailTo string,subject string, body string ) error { //定义邮箱服务器连接信息,如果是阿里邮箱 pass填密码,qq邮箱填授权码 mailConn := mapstring { "user": "zhangqiang@xxxx.com", "pass": "xxxx", "host": "smtp.mxhichina.com", "port": "465", } port, _

NeXT-Server 手动安装

38 cd /home 使用 wget 下载你选择的版本,https://go.dev/dl/ 找到适用于Linux的版本,你可以选择 .tar.gz 格式的文件以用于Debian系统 39 wget https://go.dev/dl/go1.22.4.linux-amd64.tar.gz 40 tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz 42 echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile 44 vim ~/.bashrc 编辑~/.bashrc ,一般在root目录,根据自己的情况修改,添加下面内容到.bashrc文件尾 export GO_HOME=/usr/local/go/ export GO_PATH=$HOME/go export PATH=${GO_HOME}/bin:$GO_PATH/bin:$PATH 更新当前会话以应用路径更改 45 source ~/.profile 验证Go是否安装成功 46 go version 50 apt install git 51 git --version 52 git clone https://github.com/SSPanel-NeXT/NeXT-Server 48 cd NeXt-Server/ 49 git version 56 go mod tidy 57 go build -o NextServer -ldflags "-s -w" 编辑nextServer的配置文件 vim release/config/config.yml 运行nextServer 58 ./NextServer --config config.yml