【GO】go语言中的HTTP标准库 - http编程

上一节已经学习了HTTP的基础知识,本章将学习关于go语言的HTTP编程,最重要的是掌握 net/http  包的用法,以及如何自己编写一个简单的Web服务端,通过客户端访问Server端等。

编写简单的Web 服务器

http.ListenAndServe 启动 Http Server 服务

http.HandleFunc 根据不同的路径将请求路由到不同的处理函数。

路由函数格式固定 ,必须有两个参数 (w http.ResponseWriter,r *http.Request) ,没有返回值

package main

import (
	"fmt"
	"net/http"
)

func handlerHello(w http.ResponseWriter,r *http.Request)  { // 两个参数 ,将返回参数写入到 w, 请求参数在参数r中,这里是简单的例子,所有没有使用到r参数
	fmt.Fprintf(w,"Hello World!") // 把返回内容写入 http.ResponseWriter
}

func handlerBoy(w http.ResponseWriter,r *http.Request)  {
	fmt.Fprintf(w,"hello Boy")
}

func handlerGirl(w http.ResponseWriter,r *http.Request)  {
	fmt.Fprintf(w,"hello girl")
}

func main()  {
	// 定义路由,将访问不同目录的请求 路由到 不同的处理函数
	http.HandleFunc("/",handlerHello) // 路由 ,访问 / 根目录是去执行 handlerHello,上面定义好的函数
	http.HandleFunc("/boy",handlerBoy) // 路由 ,访问/boy目录是去执行 handlerBoy
	http.HandleFunc("/girl",handlerGirl) // 第一个参数是个字符串 ,第二个参数是个函数

	// 启动HTTP server 服务,ListenAndServe 如果不发生error会一直阻塞。为每一个请求创建一个协程去处理
	if err := http.ListenAndServe(":8888",nil); err != nil { // 服务端口为 8888
		fmt.Printf("start http server fail : %s", err)
	}

}

通过浏览器请求server端

运行之后通过浏览器访问 url http://127.0.0.1:8888/,可以看到返回了 Hello World

http://127.0.0.1:8888/boy

通过浏览器访问 url http://127.0.0.1:8888/boy,返回hello Boy 

可以看到访问不同的路径返回不同的内容,这就是server端路由的作用。

通过Go编写客户端发起请求

可以都通过简单的http.Get 或者 http.Post 发送请求。

也可以通过较为复杂的 http.NewRequest 发送请求,这种方法更为灵活,可以自定义请求头,Cookie等。

另外请求req ,响应resp 中的内容可以拿出来打印或者做相应处理

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
	"time"
)

func main()  {
	get()
	post()
	complexHttpRequest()
}

// get请求
func get()  {
	resp, err :=http.Get("http://127.0.0.1:8888/boy")
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close() // 一定要调用 resp.Body.Close() ,否则会协程泄露
	io.Copy(os.Stdout,resp.Body)
	// 打印 响应头
	for k,v := range resp.Header {
		fmt.Println(k," = ", v)
	}
	fmt.Println(resp.Status) // 响应状态
	fmt.Println(resp.Proto) // http协议
}

// post请求
func post()  {
	reader:= strings.NewReader("hello server") // 新建一个io.Reader类型
	resp , err := http.Post("http://127.0.0.1:8888/girl","text/plain",reader) // 第一个参数是URL,第二个参数是 contentType 类型,第三个参数是请求正文,并不是字符串,而是io.Reader类型
	if err != nil {
		panic(err)
	}
	io.Copy(os.Stdout,resp.Body)
	defer resp.Body.Close()
	// 打印resp.Header 响应头
	for k,v := range resp.Header {
		fmt.Println(k, "==>", v)
	}
}

// 复杂的请求
func complexHttpRequest() {
	reader := strings.NewReader("hello server")
	// 创建请求,该函数接受三个参数 分别为请求方法,请求的url ,body
	req , err := http.NewRequest("POST","http://127.0.0.1:8888",reader)
	if err != nil {
		panic(err)
	}
	// 自定义请求头
	req.Header.Add("User-Agent","中国")
	req.Header.Add("MyHeaderKey","MyHeaderValue")
	// 自定义cookie
	req.AddCookie(&http.Cookie{
		Name:"yhh",
		Value: "yhh_pwd",
		Path:"/",
		Domain: "localhost",
		Expires: time.Now().Add(time.Duration(time.Hour)),
	})

	// 构建client
	client := &http.Client{
		Timeout: 100 * time.Millisecond, // 设置请求的超时时间, 100毫秒 。
	}

	// 提交http请求
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}

	// 一定要记得关闭
	defer resp.Body.Close()

	// 打印resp中的内容
	io.Copy(os.Stdout,resp.Body)

	// 打印resp header中的内容
	for k,v := range resp.Header {
		fmt.Println(k," = ", v)
	}


}

结构体Request 中文注释 

请求中的所有内容基本都在该结构体中,通过学习该结构体加深理解HTTP的基础知识

// Request代表服务器接收到的HTTP请求或客户端要发送的请求。
//
// 字段的语义在客户端和服务器的使用中略有不同。
// 除了下面字段的注释外,还请参阅Request.Write和RoundTripper的文档。
type Request struct {
    // Method指定HTTP方法(GET、POST、PUT等)。
    // 对于客户端请求,空字符串表示GET。
    //
    // Go的HTTP客户端不支持使用CONNECT方法发送请求。
    // 有关详情,请参阅Transport的文档。
    Method string

    // URL指定正在请求的URI(对于服务器请求)或要访问的URL(对于客户端请求)。
    //
    // 对于服务器请求,URL从Request-Line中提供的URI中解析。
    // 对于大多数请求,除了Path和RawQuery之外的字段将为空。(参见RFC 7230,第5.3节)
    //
    // 对于客户端请求,URL的Host指定要连接的服务器,而Request的Host字段可选择地指定要在HTTP请求中发送的Host头的值。
    URL *url.URL

    // 传入服务器请求的协议版本。
    //
    // 对于客户端请求,这些字段被忽略。HTTP客户端代码始终使用HTTP/1.1或HTTP/2。
    // 有关详情,请参阅Transport的文档。
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
    ProtoMinor int    // 0

    // Header包含要发送给服务器的请求头字段,或服务器接收的请求头字段。
    //
    // 如果服务器收到带有头行的请求,
    //
    //	Host: example.com
    //	accept-encoding: gzip, deflate
    //	Accept-Language: en-us
    //	fOO: Bar
    //	foo: two
    //
    // 则
    //
    //	Header = map[string][]string{
    //		"Accept-Encoding": {"gzip, deflate"},
    //		"Accept-Language": {"en-us"},
    //		"Foo": {"Bar", "two"},
    //	}
    //
    // 对于传入的请求,Host头将提升为Request.Host字段,并从Header映射中删除。
    //
    // HTTP定义了头名称不区分大小写。请求解析器通过使用CanonicalHeaderKey来实现这一点,
    // 使得首字母和连接符后的任何字符变为大写,其余字符变为小写。
    //
    // 对于客户端请求,某些头部,如Content-Length和Connection,在需要时会自动写入,
    // 并且Header中的值可能会被忽略。请参阅Request.Write方法的文档。
    Header Header

    // Body是请求的主体。
    //
    // 对于客户端请求,nil主体表示请求没有主体,例如GET请求。
    // HTTP客户端的Transport负责调用Close方法。
    //
    // 对于服务器请求,请求主体始终为非nil,但当没有主体时将立即返回EOF。
    // 服务器将关闭请求主体。ServeHTTP处理程序不需要这样做。
    //
    // Body必须允许在Close的同时调用Read。
    // 特别是,调用Close应该解除等待输入的Read。
    Body io.ReadCloser

    // GetBody定义了一个可选的函数,用于返回Body的新副本。
    // 当重定向需要多次读取主体时,客户端请求会使用它。
    // 使用GetBody仍然需要设置Body。
    //
    // 对于服务器请求,它未使用。
    GetBody func() (io.ReadCloser, error)

    // ContentLength记录相关内容的长度。
    // 值-1表示长度未知。
    // 值>= 0表示可以从Body读取给定字节数。
    //
    // 对于客户端请求,值为0且Body非nil也被视为未知。
    ContentLength int64

    // TransferEncoding列出了从最外层到最内层的传输编码。
    // 空列表表示“identity”编码。
    // 当发送和接收请求时,可以通常忽略TransferEncoding;
    // 在需要时,chunked编码将自动添加和删除。
    TransferEncoding []string

    // Close指示在回复此请求后(对于服务器)或发送此请求并读取其响应后(对于客户端)是否关闭连接。
    //
    // 对于服务器请求,HTTP服务器会自动处理这一点,并且处理程序不需要此字段。
    //
    // 对于客户端请求,设置此字段将防止在相同主机的请求之间重用TCP连接,就像设置了Transport.DisableKeepAlives一样。
    Close bool

    // 对于服务器请求,Host指定要搜索URL的主机。
    // 对于HTTP/1(根据RFC 7230,第5.4节),这要么是“Host”头的值,要么是URL本身中给出的主机名。
    // 对于HTTP/2,它是“:authority”伪标头字段的值。
    // 它可以是“host:port”的形式。对于国际域名,Host可能是Punycode或Unicode形式。
    // 如果需要,可以使用golang.org/x/net/idna将其转换为任何一种格式。
    // 为了防止DNS重新绑定攻击,服务器处理程序应验证Host头具有处理程序认为自己是权威的值。
    // ServeMux包含对特定主机名注册的模式,因此可以保护其注册的处理程序。
    //
    // 对于客户端请求,Host可选地覆盖要发送的Host头。
    // 如果为空,则Request.Write方法使用URL.Host的值。Host可能包含国际域名。
    Host string

    // Form包含解析的表单数据,包括URL字段的查询参数和PATCH、POST或PUT表单数据。
    // 只有在调用ParseForm之后才能使用此字段。
    // HTTP客户端会忽略Form,并使用Body。
    Form url.Values

    // PostForm包含来自PATCH、POST或PUT主体参数的解析的表单数据。
    //
    // 只有在调用ParseForm之后才能使用此字段。
    // HTTP客户端会忽略PostForm,并使用Body。
    PostForm url.Values

    // MultipartForm是解析的多部分表单,包括文件上传。
    // 只有在调用ParseMultipartForm之后才能使用此字段。
    // HTTP客户端会忽略MultipartForm,并使用Body。
    MultipartForm *multipart.Form

    // Trailer指定在请求主体之后发送的附加标头。
    //
    // 对于服务器请求,Trailer映射最初只包含尾部键,其值为nil。
    // (客户端声明它将稍后发送哪些尾部。)
    // 在处理程序从Body中读取时,它不得引用Trailer。
    // 读取自Body返回EOF后,Trailer可以再次读取,并且如果它们由客户端发送,则将包含非nil值。
    //
    // 对于客户端请求,必须将Trailer初始化为包含要稍后发送的尾部键的映射。
    // 值可以为nil或其最终值。
    // ContentLength必须为0或-1,以发送分块请求。
    // 在发送HTTP请求后,可以在读取请求主体的同时更新映射值。
    // 一旦主体返回EOF,调用者就不能改变Trailer。
    //
    // 很少有HTTP客户端、服务器或代理支持HTTP尾部。
    Trailer Header

    // RemoteAddr允许HTTP服务器和其他软件记录发送请求的网络地址,通常用于日志记录。
    // 此字段不会被ReadRequest填充,并且没有定义的格式。
    // 此包中的HTTP服务器在调用处理程序之前将RemoteAddr设置为“IP:port”地址。
    // HTTP客户端会忽略此字段。
    RemoteAddr string

    // RequestURI是由客户端发送到服务器的Request-Line(RFC 7230,第3.1.1节)的未修改的请求目标。
    // 通常应使用URL字段。
    // 在HTTP客户端请求中设置此字段是错误的。
    RequestURI string

    // TLS允许HTTP服务器和其他软件记录接收到请求的TLS连接的信息。
    // 此字段不会由ReadRequest填充。
    // 此包中的HTTP服务器在调用处理程序之前为启用TLS的连接设置字段;
    // 否则,它将保留字段为nil。
    // HTTP客户端会忽略此字段。
    TLS *tls.ConnectionState

    // Cancel是一个可选的通道,其关闭指示应将客户端请求视为已取消。
    // 并非所有的RoundTripper实现都支持Cancel。
    //
    // 对于服务器请求,此字段不适用。
    //
    // 已弃用:请使用NewRequestWithContext设置Request的上下文,而不是Cancel字段。
    // 如果一个Request的Cancel字段和上下文都被设置了,那么未定义是否Cancel会被尊重。
    Cancel <-chan struct{}

    // Response是导致创建此请求的重定向响应。此字段仅在客户端重定向期间填充。
    Response *Response

    // ctx是客户端或服务器上下文。
    // 应该仅通过复制整个Request使用WithContext来修改它。
    // 它是未导出的,以防止人们错误地使用Context并改变调用相同请求的调用者持有的上下文。
    ctx context.Context
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: "Go语言标准文手册.chm"是一份关于Go语言标准文手册文件。Go语言是一种开源的静态类型编程语言,具有高效、简洁和易于使用的特点。标准Go语言提供的一组基础性的工具和功能,开发人员可以直接使用这些来实现各种任务。 这个文手册文件提供了对Go语言标准的详细解释和示例,使开发人员能够更好地理解和使用标准的各种函数和模块。手册以CHM格式提供,这是一种常见的帮助文档文件格式,可以在Windows操作系统上方便地阅读和搜索。 通过阅读这个文手册,开发人员可以了解到标准各个模块的功能和使用方法。比如,可以学习如何使用io模块进行文件读写,如何使用net模块进行网络编程,以及如何使用fmt模块进行格式化输出等等。手册还包含了对各种常见数据结构和算法的详细解释,开发人员可以通过研究这些内容来优化自己的代码。 总之,"Go语言标准文手册.chm"是一份非常有价值的资料,它为开发人员提供了学习和使用Go语言标准的指导。通过仔细阅读这个手册,开发人员可以更加高效地使用Go语言进行开发,提高开发效率和代码质量。 ### 回答2: go语言标准文手册.chm 是一本关于Go编程语言标准文手册。它是一本电子书,采用CHM格式。在Go语言标准是非常重要的资源,它包含了许多常用的功能和模块,开发者可以直接使用这些来实现各种功能。这本文手册为开发者提供了对Go标准的详细介绍和使用指导。 这本手册由Go语言官方提供,致力于帮助开发者更好地理解和使用Go标准。它包含了标准的各个模块的详细说明,包括包名称、功能介绍、函数和方法的使用说明等。同时,手册也提供了示例代码和常见问题的解答,方便开发者快速上手和解决问题。 这本文手册的CHM格式具有很多优点。它具有方便的导航功能,可以快速查找需要的内容。同时,它支持全文搜索功能,用户可以通过关键词搜索相关内容。此外,手册的链接和交叉引用也让用户可以方便地跳转到相关章节。 对于初学者来说,这本文手册是一本宝贵的学习资料。通过阅读手册,他们可以深入了解Go标准的功能和用法,并能够利用这些来开发自己的应用程序。对于有经验的开发者来说,手册也是一个不可或缺的参考工具,它提供了对标准的全面了解,可以帮助他们更高效地开发和调试程序。 总之,go语言标准文手册.chm 是一本对于使用Go编程语言的开发者来说非常有价值的电子书。它提供了Go标准的详细介绍和使用指导,帮助开发者更好地利用标准来实现各种功能。无论是初学者还是有经验的开发者,都可以从这本手册受益匪浅。 ### 回答3: go语言标准文手册.chm是一本汇集了Go语言标准文手册。这本手册提供了Go语言标准的详细文档和示例代码,为开发者提供了查阅和学习Go语言标准的便利。 Go语言标准包含了许多常用的功能和工具,如网络通信、文件操作、并发编程、加密算法等。通过这本手册,开发者可以了解每个标准的功能和使用方法,从而更好地利用这些来开发自己的应用程序。 这本手册采用了文翻译,方便文用户理解和使用。无论是初学者还是有一定经验的开发者,都可以通过这本手册快速上手和使用Go语言标准。 由于这本手册是以.chm格式发布的,用户可以在Windows系统直接打开和阅读。同时,用户也可以将这本手册转换为其他格式,如PDF或EPUB,以便在其他设备或平台上使用。 总而言之,go语言标准文手册.chm是一本详细介绍和解释Go语言标准文手册,通过这本手册,开发者可以更好地理解和使用Go语言标准,提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DBA之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值