【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
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/616030.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

maven deploy项目发布到中央仓库签名失败signing failed: No secret key

maven deploy项目发布到中央仓库签名失败signing failed: No secret key 执行操作 在我执行命令打包项目到中央仓库时失败 mvn clean deploy错误信息 [INFO] --- gpg:3.1.0:sign (sign-artifacts) LocalCache --- [INFO] Signing 4 files with 9961AA14xxxxxxxxxxxxxxD064…

JVM 类加载机制

JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;下面我们就分别来看一下这五个过程。 加载 加载是类加载过程中的一个阶段&#xff0c;这个阶段会在内存中生成一个代表这个类的 java.lang.class 对…

【Unity 鼠标输入检测】

Unity 鼠标输入检测 Unity提供了多种方法来检测和处理鼠标输入&#xff0c;允许开发者在游戏中实现对鼠标移动、点击和滚轮滚动的响应。以下是一些基本的鼠标输入检测方法&#xff1a; 1. Input.mousePosition 这个属性返回当前鼠标指针的屏幕坐标。坐标是以像素为单位的&…

信息系统项目管理师0102:可行性研究的内容(7项目立项管理—7.2项目可行性研究—7.2.1可行性研究的内容)

点击查看专栏目录 文章目录 7.2项目可行性研究7.2.1可行性研究的内容1.技术可行性分析2.经济可行性分析3.社会效益可行性分析4.运行环境可行性分析5.其他方面的可行性分析记忆要点总结7.2项目可行性研究 可行性研究是在项目建议书被批准后,从技术、经济、社会和人员等方面的条…

【OceanBase诊断调优】—— 租户资源统计项及其查询方法

本文主要介绍 OceanBase 数据库中租户资源统计项及其查询方法。 适用版本 OceanBase 数据库 V4.1.x、V4.2.x 版本。 CPU 资源统计项 逻辑 CPU 使用率&#xff08;线程处理请求的时间占比&#xff09;。 通过虚拟表 __all_virtual_sysstat 在 SYS 系统租户下&#xff0c;查看…

【免费Java系列】大家好 ,今天是学习面向对象高级的第十二天点赞收藏关注,持续更新作品 !

这是java进阶课面向对象第一天的课程可以坐传送去学习http://t.csdnimg.cn/Lq3io day10-多线程 一、多线程常用方法 下面我们演示一下getName()、setName(String name)、currentThread()、sleep(long time)这些方法的使用效果。 public class MyThread extends Thread{publi…

AI办公自动化-用kimi批量重命名Word文档

文件夹里面有很多个word文档&#xff0c;标题里面都含有零代码编程&#xff0c;现在想将其替换为AI办公自动化。 在kimichat中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 打开文件夹&am…

Kafka和Spark Streaming的组合使用学习笔记(Spark 3.5.1)

一、安装Kafka 1.执行以下命令完成Kafka的安装&#xff1a; cd ~ //默认压缩包放在根目录 sudo tar -zxf kafka_2.12-2.6.0.tgz -C /usr/local cd /usr/local sudo mv kafka_2.12-2.6.0 kafka-2.6.0 sudo chown -R qiangzi ./kafka-2.6.0 二、启动Kafaka 1.首先需要启动K…

Github上 5 个好玩儿的开源项目

1. 在你的 Windows 养小猫 2. 把你的图片生成 ASCII 3. 中国制霸生成器 4. 像素风格代码字体 5. 梦回 QQ 空间 01 在你的 Windows 养小猫 在MacBook的触摸板上&#xff0c;你可以抚养一只小宠物&#xff0c;并与它互动、喂食&#xff0c;这样非常有趣。 我向你推荐了一个…

【Qt 学习笔记】Qt常用控件 | 容器类控件 | Group Box的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 容器类控件 | Group Box的使用及说明 文章编号&#xff…

外汇crm系统是什么

外汇CRM系统是一种专门为外汇交易市场设计的客户关系管理系统。它结合了外汇交易的特点和客户管理的需求&#xff0c;为外汇交易商提供了全面的解决方案。它的出现&#xff0c;极大地促进了外汇交易行业的发展&#xff0c;为交易商提供了更高效、更智能的客户管理方式。 一、外…

力扣每日一题124:二叉树中的最大路径和

题目 困难 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root…

08.3.grafana自定义图形

grafana自定义图形 找插件里面的zabbix 点击update 数据源—zabbix数据源,添加zabbix数据源 选择zabbix类型 我这里配置的是本地&#xff0c;所以URL直接localhost 这里配置zabbix登录账号密码Admin/zabbix 然后点击保存并测试&#xff0c;会直接显示版本 导入模板&…

电影网站|基于SSM+vue的电影网站系统(源码+数据库+文档)

电影网站 目录 基于SSMvue的电影网站系统 一、前言 二、系统设计 三、系统功能设计 1 系统功能模块 2 管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道…

虚拟机CentOS密码重置

1&#xff0c;reboot重启 在出现下面的界面1按e 如果有选项就选择“CentOS Linux &#xff08;3.10.0-327.e17.x86_64&#xff09;7 &#xff08;Core&#xff09;”【我的电脑没有直接显示界面2】 界面1 界面2 2&#xff0c;在上述界面2中继续按e进入编辑模式 找到“ro cr…

vue2和vue3区别: 探索关键差异

vue2和vue3区别&#xff1a; 探索关键差异 Vue.js 作为流行的前端框架&#xff0c;其版本 3 带来了许多令人兴奋的改进和新功能。虽然 Vue 3 保持了与 Vue 2 的相似性&#xff0c;但也存在一些关键差异需要开发者注意。本文将通过表格形式&#xff0c;清晰地展现 Vue 2 和 Vue …

文献阅读——LPPLS(2)

A study on the bursting point of Bitcoin based on the BSADF and LPPLS methods 文献来源[2] Yao, Can-Zhong, and Hong-Yu Li. “A study on the bursting point of Bitcoin based on the BSADF and LPPLS methods.” The North American Journal of Economics and Financ…

Istio 使用 Apache SkyWalking 进行服务链路追踪、链路监控告警

一、Istio 使用 Apache SkyWalking 链路追踪和告警 SkyWalking是一个开源的观测平台&#xff0c;用于从服务和云原生等基础设施中收集、分析、聚合以及可视化数据&#xff0c;SkyWalking 提供了一种简便的方式来清晰地观测分布式系统&#xff0c;甚至可以观测横跨不同云的系统…

PyCharm粘贴失灵?一文教你快速恢复!(如何解决Pycharm无法粘贴的问题)

文章目录 💢 问题 💢🏡 演示环境 🏡💯 解决方案 💯⚓️ 相关链接 ⚓️💢 问题 💢 "为什么你的代码编辑器突然变得不听话了?"最近在使用pycharm的时候遇到了一个问题,就是在pycharm中无法使用粘贴功能,后面经过一番折腾得到了解决,现在将我的解决…

03、SpringBoot 源码分析 - SpringApplication启动流程三

SpringBoot 源码分析 - SpringApplication启动流程三 初始化基本流程SpringApplication的setListeners设置监听器deduceMainApplicationClass对端主启动类rungetRunListeners获取SpringApplicationRunListener监听器EventPublishingRunListener的构造方法SimpleApplicationEven…