二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Shell编程

  • Go编程笔记

  • 前端编程笔记

  • Go学习笔记

    • 基础部分

      • 基础知识
      • 数据类型
      • fmt的格式化输入输出
      • 运算符
      • 流程控制
      • 认识函数
      • 包的操作
      • 项目工程-在同级目录
      • 指针(pointer)
      • 数组(array)
      • 切片(slice)
      • 字典(map)
      • 结构体(struct)
      • 匿名组合
      • 方法
      • 接口
      • error接口
      • panic
      • recover
      • 字符串操作
      • 字符串转换
      • 正则表达式
      • JSON处理
      • 文件的操作
      • goroutine
      • channel
      • select
      • sync-lock锁
      • 网络概述
      • Socket编程
      • 发文件与聊天室
      • http编程
        • 1,概述
          • 1,Web 工作方式
          • 2,HTTP 协议
          • 3,地址(URL)
        • 2,HTTP 报文浅析
          • 1,请求报文格式
          • 1,测试代码
          • 2,请求报文格式说明
          • 2,响应报文格式
          • 1,测试代码
          • 2,响应报文格式说明
        • 3,http 编程。
          • 1,http 服务器端。
          • 2,客户端。
      • 爬虫实战
      • 单元测试了解
    • web框架

    • orm框架

  • Vue-21年学习笔记

  • Vue-22年重学笔记

  • 编程世界
  • Go学习笔记
  • 基础部分
二丫讲梵
2021-07-10
目录

http编程

文章发布较早,内容可能过时,阅读注意甄别。

# 1,概述

# 1,Web 工作方式

我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢?

对于普通的上网过程,系统其实是这样做的:浏览器本身是一个客户端,当你输入 URL 的时候,首先浏览器会去请求 DNS 服务器,通过 DNS 获取相应的域名对应的 IP,然后通过 IP 地址找到 IP 对应的服务器后,要求建立 TCP 连接,等浏览器发送完 HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包,服务器调用自身服务,返回 HTTP Response(响应)包;客户端收到来自服务器的响应后开始渲染这个 Response 包里的主体(body),等收到全部的内容随后断开与该服务器之间的 TCP 连接。

20180119092810351

一个 Web 服务器也被称为 HTTP 服务器,它通过 HTTP 协议与客户端通信。这个客户端通常指的是 Web 浏览器 (其实手机端客户端内部也是浏览器实现的)。

Web 服务器的工作原理可以简单地归纳为:

  • 客户机通过 TCP/IP 协议建立到服务器的 TCP 连接
  • 客户端向服务器发送 HTTP 协议请求包,请求服务器里的资源文档
  • 服务器向客户机发送 HTTP 协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理 “动态内容”,并将处理得到的数据返回给客户端
  • 客户机与服务器断开。由客户端解释 HTML 文档,在客户端屏幕上渲染图形结果

# 2,HTTP 协议

超文本传输协议 (HTTP,HyperText Transfer Protocol) 是互联网上应用最为广泛的一种网络协议,它详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

HTTP 协议通常承载于 TCP 协议之上,有时也承载于 TLS 或 SSL 协议层之上,这个时候,就成了我们常说的 HTTPS。如下图所示:

20180118182133370

# 3,地址(URL)

URL 全称为 Unique Resource Location,用来表示网络资源,可以理解为网络文件路径。

URL 的格式如下:

http://host[":"port][abs_path]
http://192.168.31.1/html/index
1
2

URL 的长度有限制,不同的服务器的限制值不太相同,但是不能无限长。

# 2,HTTP 报文浅析

# 1,请求报文格式

# 1,测试代码

服务器测试代码:

package main

import (
	"fmt"
	"net"
)

func main() {
	//监听
	listener, err := net.Listen("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println("Listen err = ", err)
		return
	}
	defer listener.Close()
	//阻塞等待用户链接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("Accept err = ", err)
		return
	}
	//接收用户的请求
	buf := make([]byte, 1024)
	n, err1 := conn.Read(buf)
	if n == 0 {
		fmt.Println("Read err1 = ", err1)
		return
	}
	fmt.Printf("#%v#", string(buf[:n]))
	defer conn.Close() //关闭当前用户链接
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

先把服务器跑起来,然后在浏览器当中访问。会得到如下返回信息:

1561800959304

# 2,请求报文格式说明

HTTP 请求报文由请求行、请求头部、空行、请求包体 4 个部分组成,如下图所示:

20180118182950604

  • 1,请求行 请求行由方法字段、URL 字段 和 HTTP 协议版本字段 3 个部分组成,他们之间使用空格隔开。常用的 HTTP 请求方法有 GET、POST。

    • GET:

      • 当客户端要从服务器中读取某个资源时,使用 GET 方法。GET 方法要求服务器将 URL 定位的资源放在响应报文的数据部分,回送给客户端,即向服务器请求某个资源。
      • 使用 GET 方法时,请求参数和对应的值附加在 URL 后面,利用一个问号 (“?”) 代表 URL 的结尾与请求参数的开始,传递参数长度受限制,因此 GET 方法不适合用于上传数据。
      • 通过 GET 方法来获取网页时,参数会显示在浏览器地址栏上,因此保密性很差。
    • POST:

      • 当客户端给服务器提供信息较多时可以使用 POST 方法,POST 方法向服务器提交数据,比如完成表单数据的提交,将数据提交给服务器处理。
      • GET 一般用于获取 / 查询资源信息,POST 会附带用户数据,一般用于更新资源信息。POST 方法将请求参数封装在 HTTP 请求数据中,而且长度没有限制,因为 POST 携带的数据,在 HTTP 的请求正文中,以名称 / 值的形式出现,可以传输大量数据。
  • 2,请求头部 请求头部为请求报文添加了一些附加信息,由 “名 / 值” 对组成,每行一对,名和值之间使用冒号分隔。

    请求头部通知服务器有关于客户端请求的信息,典型的请求头有:

    请求头 含义
    User-Agent 请求的浏览器类型
    Accept 客户端可识别的响应内容类型列表,星号 “” 用于按范围将类型分组,用“ / ”指示可接受全部类型,用 “type/” 指示可接受 type 类型的所有子类型
    Accept-Language 客户端可接受的自然语言
    Accept-Encoding 客户端可接受的编码压缩格式
    Accept-Charset 可接受的应答的字符集
    Host 请求的主机名,允许多个域名同处一个 IP 地址,即虚拟主机
    connection 连接方式 (close 或 keepalive)
    Cookie 存储于客户端扩展字段,向同一域名的服务端发送属于该域的 cookie
  • 3,空行 最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。

  • 4,请求包体 请求包体不在 GET 方法中使用,而是 POST 方法中使用。 POST 方法适用于需要客户填写表单的场合。与请求包体相关的最常使用的是包体类型 Content-Type 和包体长度 Content-Length。

# 2,响应报文格式

# 1,测试代码

服务器示例代码:

package main

import (
	"fmt"
	"net/http"
)

//服务端编写的业务逻辑处理程序
func myHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello world")
}

func main() {
	http.HandleFunc("/go", myHandler)

	//在指定的地址进行监听,开启一个HTTP
	http.ListenAndServe("127.0.0.1:8000", nil)

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

然后启动服务器程序,等待客户端连接。

客户端测试示例代码:

package main

import (
	"fmt"
	"net"
)

func main() {
	//主动连接服务器
	conn, err := net.Dial("tcp", ":8000")
	if err != nil {
		fmt.Println("Dial err = ", err)
	}
	defer conn.Close()

	requstBuf := "GET /go HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, */*\r\nAccept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)\r\nAccept-Encoding: gzip, deflate\r\nHost: 127.0.0.1:8000\r\nConnection: Keep-Alive\r\n\r\n"

	//先发送请求包,等待服务器返回响应包
	conn.Write([]byte(requstBuf))

	//接收服务器恢复的响应包
	buf := make([]byte, 1024*4)
	n, err := conn.Read(buf)
	if n == 0 {
		fmt.Println("Read err = ", err)
		return
	}
	//打印相应报文
	fmt.Printf("#%v#", string(buf[:n]))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

启动程序,测试 http 的成功响应报文:

20180118183845248

启动程序,测试 http 的失败响应报文:

20180118183905290

# 2,响应报文格式说明

HTTP 响应报文由状态行、响应头部、空行、响应包体 4 个部分组成,如下图所示:

20180118183941397

  • 1,状态行

    状态行由 HTTP 协议版本字段、状态码和状态码的描述文本 3 个部分组成,他们之间使用空格隔开。

    状态码由三位数字组成,第一位数字表示响应的类型,常用的状态码有五大类如下所示:

    状态码 含义
    1xx 表示服务器已接收了客户端请求,客户端可继续发送请求
    2xx 表示服务器已成功接收到请求并进行处理
    3xx 表示服务器要求客户端重定向
    4xx 表示客户端的请求有非法内容
    5xx 表示服务器未能正常处理客户端的请求而出现意外错误

    常见的状态码举例:

    状态码 含义
    200 OK 客户端请求成功
    400 Bad Request 请求报文有语法错误
    401 Unauthorized 未授权
    403 Forbidden 服务器拒绝服务
    404 Not Found 请求的资源不存在
    500 Internal Server Error 服务器内部错误
    503 Server Unavailable 服务器临时不能处理客户端请求 (稍后可能可以)
  • 2,响应头部

    响应头可能包括:

    响应头 含义
    Location Location 响应报头域用于重定向接受者到一个新的位置
    Server Server 响应报头域包含了服务器用来处理请求的软件信息及其版本
    Vary 指示不可缓存的请求头列表
    Connection 连接方式
  • 3,空行

    最后一个响应头部之后是一个空行,发送回车符和换行符,通知服务器以下不再有响应头部。

  • 4,响应包体

    服务器返回给客户端的文本信息。

# 3,http 编程。

Go 语言标准库内建提供了 net/http 包,涵盖了 HTTP 客户端和服务端的具体实现。使用 net/http 包,我们可以很方便地编写 HTTP 客户端或服务端的程序。

# 1,http 服务器端。

代码如下:

package main

import (
	"fmt"
	"net/http"
)

//w,给客户端回复数据
//req,读取客户端发送的数据
func HandConn(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.RemoteAddr, "连接成功") //远程网络地址
	fmt.Println(req.Method)             //请求方法
	fmt.Println(req.URL.Path)
	fmt.Println(req.Header)
	fmt.Println(req.Body)

	w.Write([]byte("hello world")) //给客户端返回数据
}
func main() {
	//注册处理函数,用户连接,自动调用指定的处理函数
	http.HandleFunc("/eryajf", HandConn)

	//监听绑定
	http.ListenAndServe(":8000", nil)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

运行之后,使用 postman 进行 get 请求:

1561805991019

# 2,客户端。

现在写一个客户端。

package main

import (
	"fmt"
	"net/http"
)

func main() {
	resp, err := http.Get("http://127.0.0.1:8000/eryajf")
	if err != nil {
		fmt.Println("Get err = ", err)
		return
	}
	defer resp.Body.Close()

	fmt.Println("status = ", resp.Status)
	fmt.Println("StatusCode = ", resp.StatusCode)
	fmt.Println("Header = ", resp.Header)
	//fmt.Println("body = ", resp.Body)

	buf := make([]byte, 4*1024)
	var tmp string
	for {
		n, err := resp.Body.Read(buf)
		if n == 0 {
			fmt.Println("read err = ", err)
			break
		}
		tmp += string(buf[:n])
	}
	fmt.Println("tmp = ", tmp)

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

首先运行上边的服务端,然后再运行下边的客户端,得到如下内容:

$ go run 5_http客户端.go
status =  200 OK
StatusCode =  200
Header =  map[Date:[Sat, 29 Jun 2019 11:16:40 GMT] Content-Length:[11] Content-Type:[text/plain; charset=utf-8]]
read err =  EOF
tmp =  hello world
1
2
3
4
5
6
微信 支付宝
#go
上次更新: 2024/07/04, 22:40:37
发文件与聊天室
爬虫实战

← 发文件与聊天室 爬虫实战→

最近更新
01
记录二五年五一之短暂回归家庭
05-09
02
学习周刊-总第210期-2025年第19周
05-09
03
学习周刊-总第209期-2025年第18周
05-03
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式