go 进阶 http标准库相关: 一. HttpServer HttpClient 基础相关

  1. 在 Golang 的net/http 标准库很强大,可以实现一下功能
  1. 实现 HTTP 请求客户端:可以通过 http.Client 对象和 http.NewRequest 方法发送 HTTP 请求。
  2. 实现 HTTP 服务器:可以通过 http.ListenAndServe 和 http.HandleFunc 方法构建简单的 HTTP 服务器。
  3. 实现 WebSocket 服务:net/http 提供了 http.HandlerFunc 类型,可以方便地实现 WebSocket 服务。
  4. 支持 HTTPS 加密协议:net/http 可以通过 http.ListenAndServeTLS 方法来支持 HTTPS 协议,保证网络安全性。
  5. 支持 Cookie:net/http 可以通过 http.Cookie 和 CookieJar 等类型来设置和管理 Cookie。
  6. 支持文件传输:net/http 可以通过 http.ServeFile 方法来实现基于 HTTP 的文件传输服务,支持断点续传等功能。
  1. net/http 客户端下几个常见的API总结
//发送一个 GET 请求并返回响应结果
func Get(url string) (resp *http.Response, err error)
//发送 POST 请求并返回响应结果
func Post(url, contentType string, body io.Reader) (resp *http.Response, err error)
//发送一个 POST 表单请求并返回响应结果
func PostForm(url string, data url.Values) (resp *http.Response, err error)
//发送指定类型的 HTTP 请求,并返回响应结果。可以使用该方法发送任意类型的 HTTP 请求,例如 GET、POST、PUT、DELETE 等
func Do(req *http.Request) (resp *http.Response, err error)
//发送一个 HEAD 请求并返回响应结果
func Head(url string) (resp *http.Response, err error)
//创建一个 HTTP 请求对象。可以通过传入请求方法、请求 URL 和请求体等参数来创建一个 HTTP 请求对象
func NewRequest(method, url string, body io.Reader) (*http.Request, error)
//创建一个上传文件的 HTTP 请求对象,并返回请求对象。可以通过传入 URL 地址、附加参数、文件参数名称和文件路径等参数来创建一个 HTTP 文件上传请求对象
func NewFileUploadRequest(url string, params map[string]string, paramName, path string) (*http.Request, error)
//定义重定向策略函数。可以传入一个自定义的重定向策略函数,用于处理 HTTP 请求重定向过程中的行为
func RedirectPolicyFunc(f func(*http.Request, []*http.Request) error) func(*http.Request, []*http.Request) error
//执行默认的重定向策略。在发送 HTTP 请求时,如果遇到 3xx 类型的 HTTP 响应,就需要执行重定向策略来决定是否继续重定向和如何重定向
func CheckRedirect(req *http.Request, via []*http.Request) error
//定义超时处理器。可以通过传入一个超时时间、一个提示消息和一个 HTTP 处理器等参数来创建一个超时处理器对象,用于控制 HTTP 请求的超时处理行为
func TimeoutHandler(h http.Handler, dt time.Duration, msg string) http.Handler
//创建一个带超时时间的 HTTP 客户端。可以通过传入时间参数来创建一个带有超时处理机制的 HTTP 客户端对象
func WithTimeout(timeout time.Duration) *http.Client
//创建一个 HTTP 客户端对象。可以通过传入自定义的 HTTP 客户端参数,如超时时间、传输协议类型等,来创建一个新的客户端对象
func NewClient(c *http.Client) *http.Client
//限制读取数据的最大字节数。可以使用该函数创建一个读取数据的流处理器,限制数据的读取数量,保证 Web 应用程序的安全性和稳定性
func MaxBytesReader(w http.ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser
//设置客户端 Cookie。可以使用该函数创建并设置一个 HTTP Cookie 对象,将其添加到 HTTP 响应头信息中,发送给客户端浏览器
func SetCookie(w http.ResponseWriter, cookie *http.Cookie)
//读取 HTTP 请求。可以通过传入一个 bufio.Reader 类型的参数,逐行读取 HTTP 请求,返回一个 HTTP 请求对象和一个错误信息
func ReadRequest(b *bufio.Reader) (*http.Request, error)
//获取 HTTP 请求的 User-Agent 信息。可以使用该函数获取客户端浏览器或者其他客户端工具的 User-Agent 信息,以便对请求进行分析和处理
func UserAgent(r *http.Request) string
//解析 HTTP 协议版本。可以使用该函数解析 HTTP 协议的版本字段,返回协议的主版本号和次版本号等信息
func ParseHTTPVersion(vers string) (major, minor int, ok bool)
  1. net/http 服务端下几个常见的API总结
//启动一个 HTTP 服务器并监听指定地址和端口号。可以通过传入 HTTP 处理器来指定服务器的请求处理方式
func ListenAndServe(addr string, handler http.Handler) error
//启动基于 TLS 协议的 HTTPS 服务器。可以使用该 API 创建一个支持 HTTPS 协议的 Web 服务器,并提供 SSL/TLS 安全加密传输服务
func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error
//定义静态文件服务器。可以通过传入文件根目录等参数来创建一个 HTTP 静态文件服务器
func FileServer(root http.FileSystem) http.Handler
//定义 404 响应处理器。可以使用该 API 定义一个默认的 404 错误处理器,用于处理无法找到指定资源时的 HTTP 请求
func NotFound(w http.ResponseWriter, r *http.Request)
//定义重定向响应处理器。可以使用该 API 定义一个默认的重定向处理器,用于在 Web 应用程序中实现 HTTP 重定向行为
func Redirect(w http.ResponseWriter, r *http.Request, url string, code int)
//定义前缀删除处理器。可以使用该 API 创建一个新的 HTTP 处理器对象,并移除请求 URL 中指定的前缀部分,然后再将剩余的路径信息传递给路由映射器进行处理
func StripPrefix(prefix string, h http.Handler) http.Handler
//创建一个新的 HTTP 服务路由器对象。可以使用该函数创建一个新的 HTTP 服务路由器,将不同的 URL 地址映射到不同的 HTTP 处理器上
func NewServeMux() *http.ServeMux
//注册 HTTP 请求处理器。可以使用该函数将一个 HTTP 处理器注册到指定的 URL 地址上
func HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
//注册 HTTP 请求处理器。可以使用该函数将一个 HTTP 处理器注册到指定的 URL 地址上
func Handle(pattern string, handler http.Handler)
//默认的 404 响应处理器。可以使用该函数获取一个默认的 404 错误处理器,用于在 Web 应用程序中实现 404 错误页面的提示和处理
func NotFoundHandler() http.Handler
//定义前缀删除处理器。可以使用该函数创建一个新的 HTTP 处理器对象,并移除请求 URL 中指定的前缀部分,然后再将剩余的路径信息传递给路由映射器进行处理
func StripPrefix(prefix string, h http.Handler) http.Handler

一. HttpServer

该文档中重点参考大神博客一,二,三

  1. 先编写一个http服务器示例
  1. 实现HandlerFunc编写处理器函数(在下方""通过DefaultServeMux了解路由的注册流程"步骤中又讲为什么是实现HandlerFunc,也可以创建结构体实现ServeHTTP编写处理器)
  2. 通过http的HandleFunc函数注册接口,将处理器与接口绑定,也称为注册路由
  3. 监听指定地址端口
  4. 运行main方法启动服务
import (
	"fmt"
	"log"
	"net/http"
)

//1.自定义处理器,固定格式包含两个入参http.ResponseWriter 与 r *http.Request
//http.ResponseWriter: 通过它将响应发送给客户端
//http.Request的结构指针: 通过它获取客户端传递过来的数据
func httpExecute(w http.ResponseWriter, r *http.Request) {
	//将响应写入 http.ResponseWriter 中
	fmt.Fprintf(w, "<h1>Hello, Web!</h1>")
}

func main() {
	//2.通过内部http调用HandleFunc()注册一个http请求接口,也成为注册处理器,
	//将执行业务的处理器与对应的接口路径进行绑定
	//第一个参数是路由表达式,也就是请求路径
	//第二个参数是一个函数类型,也就是真正处理请求的函数
	http.HandleFunc("/hello", httpExecute)

	//3.通过http调用ListenAndServe()方法监听8080端口(冒号前面不写代表localhost)
	if err := http.ListenAndServe(":8080", nil); err != nil {
		//当err不为空时,打印异常日志
		log.Fatal(err)
	}
}
  1. 此时在浏览器输入http://localhost:8080/hello 得到输出 hello world,以上代码重点可分为三块

编写请求处理函数(实现处理器接口)

 httpExecute(w http.ResponseWriter, r *http.Request)

注册路由

http.HandleFunc("/hello", httpExecute)

监听端口启动服务

 http.ListenAndServe(":8080", nil)

1. 创建多路复⽤器

  1. 虽然默认的多路复⽤器使⽤起来很⽅便,但是在⽣产环境中不建议使⽤。因为 DefaultServeMux 是⼀个全局变量,所有代码,包括第三⽅代码都可以修改它。 有些第三⽅代码会在 DefaultServeMux 注册⼀些处理器,这可能与我们注册的处理器冲突
  2. 代码示例
import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func main() {
	//1.创建多路复用器Mux
	mux := http.NewServeMux()

	//2.注册处理器(也就是请求接口)
	mux.HandleFunc("/hello", helloFunc)

	//3.创建服务器对象,指定当前端口号,并设置多路复用器
	server := &http.Server{
		Addr: ":8080",
		Handler: mux, //注册处理器
		//不是必须要的
		ReadTimeout: 1 * time.Second, //设置请求接口的读超时时间
		WriteTimeout: 1 * time.Second, //设置请求接口的写超时时间
	}
	
	//4.通过设置好端口,多路复用器的server启动监听
	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

//业务接口
func helloFunc(w http.ResponseWriter, r *http.Request) {
	//将响应写入 http.ResponseWriter 中
	fmt.Fprintf(w, "<h1>Hello, Web!</h1>")
}

2. http.Request 请求参数相关

  1. 解释在上面编写示例时发现,在http接口的入参出有"http.ResponseWriter"与"*http.Request",接收与响应的参数都在这两个结构里
  2. 了解http.Request结构

1.Method : 表示客户端想要调⽤服务器的 HTTP 协议⽅法,例如GET/POST/PUT/DELETE 等
2. URL : 被称为统⼀资源标识符, 由两部分组成统⼀资源名称与统⼀资源定位符,在go中也是一个结构体

// src/net/http/request.go
type Request struct {
 Method string //请求方法,例如GET,POST等等
 URL *url.URL
 Proto string //http协议版本例如HTTP1.1
 ProtoMajor int //http协议版本,1
 ProtoMinor int //http协议版本相关 1
 Header Header //请求头
 Body io.ReadCloser //请求体内容
 ContentLength int //请求体的字节长度
 // 省略⼀些字段...
}

URL的解释

//在go中的结构
// net/url/url.go
type URL struct {
 Scheme string
 Opaque string
 User *Userinfo
 Host string
 Path string
 RawPath string
 RawQuery string
 Fragment string
}

在这里插入图片描述

  1. URL注意点: 如果在接口同通过 *http.Request.URL 拿到URL后,如果想继续获取URL中的数据时,只能读到URL.Path与URL.RawQuery
  2. 我们可以通过net去获取url中的相关数据,假设前端发送get请求为"问 localhost:8080/url/posts?page=1&count=10#main ",后端可以
URL := &net.URL {
 Scheme: "http",
 Host: "example.com",
 Path: "/posts",
 RawQuery: "page=1&count=10",
 Fragment: "main", }
 //输出 http://example.com/posts?page=1&count=10#main
fmt.Println(URL.String())

Header 请求头

  1. 请求头解释
// src/net/http/header.go
type Header map[string][]string

在这里插入图片描述
2. 请求接口,获取请求头中的数据

func headerHandler(w http.ResponseWriter, r *http.Request) {
	for key, value := range r.Header {
		fmt.Fprintf(w, "%s: %v\n", key, value)
	}
}

Body/Content-Length

  1. Content-Length 表示请求体的字节⻓度
  2. 请求体的内容可以从 Body 字段中读取。Body 字段是⼀个 io.ReadCloser 接⼝。在读取之后要关闭它,否则会有资源泄露
  3. 请求接口读取body
func bodyHandler(w http.ResponseWriter, r *http.Request) {
 data := make([]byte, r.ContentLength)
 r.Body.Read(data) // 忽略错误处理
 //通过defer关闭
 defer r.Body.Close()
 //如果想客户端传来的请求体内容回传给客户端,还可以使⽤ io/ioutil下的ReadAll()
 //data, _ := ioutil.ReadAll(r.Body)
 fmt.Fprintln(w, string(data))
}

获取请求参数

  1. URL 键值对例如: key1=value1&key2=value2,通过http.Request中的URL中的RawQuery获取
  2. 例如:发送":8080/query?name=ls&age=20" 请求
func queryHandler(w http.ResponseWriter, r *http.Request) {
 //返回"name=ls&age=20"
 fmt.Fprintln(w, r.URL.RawQuery) 
}
  1. 处理"x-www-form-urlencoded" 编码的请求体,注意点处理时⾸先调⽤请求的 ParseForm ⽅法解析,然后
    从 Form 字段中取数据,Form 字段的类型 url.Values 底层实际上是 map[string][]string 。调⽤ ParseForm ⽅法之后,可
    以使⽤ url.Values 的⽅法操作数据
func formHandler(w http.ResponseWriter, r *http.Request) {
 r.ParseForm()
 fmt.Fprintln(w, r.Form) 
}
  1. PostForm 字段,如果⼀个请求,同时有 URL 键值对和表单数据,只想获取表单数据,可以使⽤ PostForm 字段, 只会返回表单数据,不包括 URL 键值
  2. MultipartForm 字段,如果要处理上传的⽂件,必须使⽤ multipart/form-data 编码,也需要先解析后使⽤,使⽤ ParseMultipartForm ,之后从 MultipartForm 字段取值
func multipartFormHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseMultipartForm(1024)
	fmt.Fprintln(w, r.MultipartForm)

	fileHeader := r.MultipartForm.File["uploaded"][0]
	file, err := fileHeader.Open()
	if err != nil {
		fmt.Println("Open failed: ", err)
		return
	}
	data, err := ioutil.ReadAll(file)
	if err == nil {
		fmt.Fprintln(w, string(data))
	}
}
  1. MultipartForm 包含两个 map 类型的字段,⼀个表示表单键值对,⼀个为上传的⽂件信息,使⽤表单中⽂件控件名获取 MultipartForm.File 得到通过该控件上传的⽂件,可以是多个。是 multipart.FileHeader 类型,通过该类型可以获取⽂件的各个属性。,注意点,该⽅式⽤来处理⽂件,为了安全, ParseMultipartForm ⽅法需要传⼀个参数,表示最⼤使⽤内存,避免上传的⽂件占⽤空间过⼤
  2. FormValue/PostFormValue :为了⽅便地获取值, net/http 包提供了 FormValue/PostFormValue ⽅法。它们在需要时会⾃动调⽤ ParseForm/ParseMultipartForm ⽅法,FormValue ⽅法返回请求的 Form 字段中指定键的值。如果同⼀个键对应多个值,那么返回第⼀个。如果需要获取全部值,直接使⽤ Form 字段。下⾯代码将返回 hello 对应的第⼀个值
fmt.Fprintln(w, r.FormValue("hello"))
  1. PostFormValue ⽅法返回请求的 PostForm 字段中指定键的值。如果同⼀个键对应多个值,那么返回第⼀个。如果需要获取全部值,直接使⽤ PostForm 字段
  2. 注意: 当编码被指定为 multipart/form-data 时, FormValue/PostFormValue 将不会返回任何值,
    它们读取的是 Form/PostForm 字段,⽽ ParseMultipartForm 将数据写⼊ MultipartForm 字段

3. http.ResponseWriter 响应参数相关

  1. 在响应调用方时使用net/http 包中的ResponseWriter
// src/net/http/
type ReponseWriter interface {
 Header() Header
 Write([]byte) (int, error)
 WriteHeader(statusCode int) }
  1. 接收请求后多路复⽤器会⾃动创建⼀个实现了http.ResponseWriter 接⼝的 http.response 对象,然后将该对象的指针和请求对象作为参数传给处理器,使⽤指针是为了能在处理逻辑中⽅便地获取请求信息
  2. ResponseWriter 有三个方法,Write(), WriteHeader(), Header(),通过这 3 个⽅法,响应调用方例如上面使用的 fmt.Fprintln(w, “Hello,
    Web”) 其实底层调⽤了 Write ⽅法
  3. Write([]byte) (int, error) ⽅法, ResponseWriter不但实现了该方法并且也实现了 io.Writer 接⼝,在上面fmt.Fprintln 的第
    ⼀个参数接收⼀个 io.Writer 接⼝,这就是fmt.Fprintln可以正常执行的原因
  4. 也可以通过 ResponseWriter 直接调用Write()进行响应
func writeHandler(w http.ResponseWriter, r *http.Request) {
 str := `<html>响应数据</html>`
 w.Write([]byte(str))
}

WriteHeader ⽅法

  1. 注意点:WriteHeader ⽅法并不能⽤于设置响应⾸部,WriteHeader 接收⼀个整数,并将这个整数作为 HTTP 响应的状态码返回,调⽤这个返回之后,可以继续对 ResponseWriter 进⾏写⼊,但是不能对响应的⾸部进⾏任何修改操作。如果⽤户在调⽤ Write ⽅法之前没有执⾏过
    WriteHeader ⽅法,那么程序默认会使⽤ 200 作为响应的状态码
  2. 通过WriteHeader 手动返回501示例
func writeHeaderHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(501)
	fmt.Fprintln(w, "This API not implemented!!!") 
}

Header ⽅法

  1. 解释: Header ⽅法其实返回的是⼀个 http.Header 类型,该类型的底层为 map[string][]string,该Header 类型中定义了 CRUD ⽅法,可以通过这些⽅法操作⾸部
// src/net/http/header.go
type Header map[string][]string
  1. 通过 Header 设置重定向
func headerHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Location", "http://baidu.com")
	// 302 表示重定向
	w.WriteHeader(302) 
}
  1. 通过Header设置响应格式为JSON示例
func jsonHandler(w http.ResponseWriter, r *http.Request) {
	//添加响应首部
 	w.Header().Set("Content-Type", "application/json")
 	//创建响应参数
 	u := &User {
 		FirstName: "ls",
 		LastName: "ls",
 		Age: 18,
 		Hobbies: []string{"reading", "learning"},
 	}
 	//将响应参数序列化为JSON
 	data, _ := json.Marshal(u)
 	//响应
 	w.Write(data) 
}

4. cookie 相关

  1. Go 中 cookie 使⽤ net/http 包下的 http.Cookie 结构表示
// src/net/http/cookie.go
type Cookie struct {
 Name string //键
 Value string //值
 Path string
 Domain string
 Expires time.Time //没有设置 Expires 字段的 cookie 被称为会话 cookie 或临时 cookie,关闭浏览器自动删除
 RawExpires string
 MaxAge int
 Secure bool
 HttpOnly bool //HttpOnly 字段设置为 true 时,该 cookie 只能通过 HTTP 访问,如JavaScript
 SameSite SameSite
 Raw string
 Unparsed []string
}
//注意点:Expires 和 MaxAge 都可以⽤于设置 cookie 的过期时间。
//Expires 字段设置的是 cookie 在什么时间点过期,
//⽽ MaxAge 字段表示 cookie ⾃创建之后能够存活多少秒
// HTTP 1.1 中废弃了Expires ,推荐使⽤ MaxAge 代替。但是⼏乎所有的浏览器都仍然⽀持 Expires
  1. cookie 需要通过响应的⾸部发送给客户端,浏览器收到 Set-Cookie ⾸部时,会将其中的值解析成cookie 格式保存在浏览器中
func setCookie(w http.ResponseWriter, r *http.Request) {
	c1 := &http.Cookie{
		Name:     "name",
		Value:    "lianshi",
		HttpOnly: true,
	}
	c2 := &http.Cookie{
		Name:     "age",
		Value:    "18",
		HttpOnly: true,
	}
	w.Header().Set("Set-Cookie", c1.String())
	w.Header().Add("Set-Cookie", c2.String())
}
  1. 为了使⽤的便捷, net/http 包还提供了 SetCookie ⽅法
func setCookie2(w http.ResponseWriter, r *http.Request) {
	c1 := &http.Cookie{
		Name:     "name",
		Value:    "lianshi",
		HttpOnly: true,
	}
	c2 := &http.Cookie{
		Name:     "age",
		Value:    "18",
		HttpOnly: true,
	}
	http.SetCookie(w, c1)
	http.SetCookie(w, c2)
}
  1. 请求接口中读取cookie,注意点r.Header[“Cookie”] 返回⼀个切⽚,这个切⽚⼜包含了⼀个字符串,⽽这个字符串⼜包含了客户端发
    送的任意多个 cookie。如果想要取得单个键值对格式的 cookie,就需要解析这个字符串。 为此, net/http 包在 http.Request 上提供了⼀些⽅法使我们更容易地获取 cookie
func getCookie2(w http.ResponseWriter, r *http.Request) {
	//Cookie ⽅法返回以传⼊参数为键的 cookie,如果该 cookie 不存在,则返回⼀个错误
	name, err := r.Cookie("name")
	if err != nil {
		fmt.Fprintln(w, "cannot get cookie of name")
	}
	//Cookies ⽅法返回客户端传过来的所有 cookie
	cookies := r.Cookies()
	fmt.Fprintln(w, name)
	fmt.Fprintln(w, cookies)
}

二. HttpClient

1. 封装http客户端简单示例

  1. 封装客户端与发送http请求代码简单示例
func ClentServer() {
	//1.创建客户端连接池
	transport := &http.Transport{
		//拨号配置上下文
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second, //连接超时时间
			KeepAlive: 30 * time.Second, //探活时间
		}).DialContext,
		MaxIdleConns:          100,              //最大空闲连接
		IdleConnTimeout:       90 * time.Second, //空闲超时时间
		TLSHandshakeTimeout:   10 * time.Second, //tls握手超时时间
		ExpectContinueTimeout: 1 * time.Second,  //100-continue状态码超时时间
	}
	//2.创建客户端
	client := &http.Client{
		Timeout:   time.Second * 30, //请求超时时间
		Transport: transport,        //绑定连接池
	}

	//3.客户端发送get请求示例
	clientSendGet(client)

	//4.客户端发起post请求示例
	clientSendPost(client)

}

func clientSendGet(client *http.Client) {
	resp, err := client.Get("http://127.0.0.1:8080/test")
	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
	}
	fmt.Println(string(body))
}

func clientSendPost(client *http.Client) {
	resp, err := client.Post("http://127.0.0.1:8080/test", "application/json", strings.NewReader("name=val"))
	if err != nil {
		fmt.Println(err)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
	}

	fmt.Println(string(body))
}
  1. 几种发送请求的代码示例
// 发送GET请求
// url:请求地址
// response:请求返回的内容
func Get(url string) (response string, err error) {
	client := http.Client{Timeout: 5 * time.Second}
	resp, error := client.Get(url)
	if error != nil {
		return "", error
	}
	defer resp.Body.Close()
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			return "", error
		}
	}

	response = result.String()
	return response, nil
}

func clientSendPost2(client *http.Client) {
	resp, err := client.PostForm("http://127.0.0.1:8080/test", url.Values{"key": {"Value"}, "id": {"123"}})
	if err != nil {
		// handle error
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
	}

	fmt.Println(string(body))
}

func httpDo() {
	client := &http.Client{}
	req, err := http.NewRequest("POST", "http://127.0.0.1:8080/testp", strings.NewReader("name=小明"))
	if err != nil {
		// handle error
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Cookie", "name=anny")

	resp, err := client.Do(req)

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
	}
	fmt.Println(string(body))
}

2. 生产上基于原生http发送post请求示例

//url:请求url
//data:请求参数
//返回string字符串,异常时error不为空
func AdapterPost(url string, data interface{}) (string, error) {
	jsonStr, _ := json.Marshal(data)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	if err != nil {
		return "", err
	}
	req.Header.Add("Content-type", "application/json")
	req.Header.Add("msgid", "ssss")

	client := &http.Client{Timeout: 60 * time.Second}
	resp, error := client.Do(req)
	defer resp.Body.Close()
	if error != nil {
		return "", error
	}

	result, _ := ioutil.ReadAll(resp.Body)
	ret := string(result)
	return ret, nil
}

3. 生产上基于三方库发送请求示例

//使用三方库发送请求示例: github.com/go-resty/resty/v2
//method:请求方法
//url:请求url
//headers:请求头
//data:请求参数
//result:响应数据结构(获取到响应后直接转换为指定结构)
func DoSend(method, url string, headers map[string]string, data interface{}, result interface{}) error {

	/*jsonByte, _ := json.Marshal(data)
	dataStr := string(jsonByte)
	log.TraceLog("", "AdapterReq|Post|0|%s|%s", url, dataStr)*/

	client := resty.New()
	client.SetTimeout(60 * time.Second)
	request := client.R().
		SetHeaders(headers).
		SetBody(data).
		SetResult(result)
	var resp *resty.Response
	var err error
	if "GET" == method {
		resp, err = request.Get(url)
	} else {
		resp, err = request.Post(url)
	}

	if err != nil {
		return err
	}

	if !resp.IsSuccess() {
		//errMsg := resp.RawResponse.Status
		return nil //err
	}

	respJsonByte, err := json.Marshal(result)
	if err != nil {

		return err
	}
	respStr := string(respJsonByte)
	fmt.Print(respStr)

	return nil
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值