#11 HTTP/2 的几个特性
HTTP 2022-08-20Server Push服务器主动推送资源,客户端请求 A 的时候,服务器把 A 相关的资源 B, C, D 都一起推送给客户端。-
Early HintsHTTP 103 状态码。客户端请求 A 的时候,- 如果是普通情况,服务器返回 200 状态码,带上资源信息
- 如果应用上 Early Hints,服务器返回 103 状态码,带上需要资源信息(Link 头),然后是资源信息
好处就是节省了浏览器解析 HTML 获取子资源信息的延迟。刚解析 103 头,就可以开始请求子资源了。
就最近的几个月,主流浏览器开始提供支持。 -
Preload Critical Assets就是 HTML link 头中的rel="preload",提前加载文件,避免按照文件解析生成的调用链顺序来加载,而提升资源加载速度。
Chrome 将禁用 HTTP/2 服务器推送(Server Push)支持
谷歌博客显示,在 Chrome 106 和其他基于 Chromium 的浏览器的下个版本中,默认情况下将禁用对 HTTP/2 服务器推送(HTTP/2 Server Push)的支持。
HTTP/2 允许服务器在实际请求之前 “推送” 服务端可能需要的资源, HTTP/2 的 Server Push 特性解决了 HTTP/1.x 的无脑按顺序加载资源的问题,本意是提高网页的响应性能。
然而这功能逻辑本身就有问题,比如资源存放在单个业务服务器上,并行推送多个静态资源只会降低响应速度,性能不升反降。而对于前后端分离的业务来说,HTTP/2 本身就支持多路复用,server push 只能稍微降低浏览器解析 html 的时间,对现代浏览器来说性能提升可以忽略不计。
HTTP/2 时代也只有 1.25% 的 HTTP/2 站点使用了这个特性。在 HTTP/3 出来之后,该功能更是彻底被遗忘了,最新的分析中,网站对 HTTP/2 的支持率从 1.25% 下降到 0.7%。
替代方案
103 Early Hints 是 Server Push 的首选替代方案,它具有 Push 的许多优点,而缺点则少得多。与服务器推送资源不同,103 Early Hints 只向浏览器发送可能受益于请求的资源提示。浏览器可以控制它是否需要这些资源,比如浏览器已经在 HTTP 缓存中拥有这些资源,则无需额外加载。
预加载关键资源是另一种选择,它允许页面和浏览器一起工作,在页面加载的早期抢先加载关键资源。它不如 Server Push 或 Early Hints 快 —— 但它不会延迟关键页面资源,而另外两种解决方案都可能发生这种情况。
参考资料与拓展阅读
- 知乎专栏,详解 HTTP/2 Server Push——进一步提升页面加载速度
- 掘金,HTTP 新增的 103 状态码,这次终于派上用场了!
- https://web.dev/i18n/zh/preload-critical-assets/
- 2018/12/13, Python 与 HTTP/2
- 2019/09/23, HTTP/2
- 2020/06/01, Nginx HTTP/2 部署
- 2021/08/03, Curl HTTP/2
- 2021/08/18, Go HTTP/2
- 2021/08/29, Python 与 HTTP/2 (2021)
- 2022/08/06, Gin HTTP/2
#10 HTTP 协议新提案:Query 方法
HTTP 2022-04-15令我惊讶的是,竟然还有人不是为了解决什么痛点问题,而想对一个使用如此广泛的基础协议做改动。
我敢打赌,绝对不可能通过。
https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-02.html
这个新提案的主要理由是 URL 中不能包含太多数据(实现的限制),然后受 URL 编码的影响,效率下降。
作者认为应该设计一个支持 Body 的 GET 方法,那就是 Query。
提案讨论了相关的缓存问题。要求将 URL 和 Body 合并成 Key。
可以在这里跟踪相关进展:
#9 HTTP 超时相关的疑问
Linux HTTP 2022-02-25今天发现一个奇怪的现象,相同的代码在 CentOS 7 服务器上发起 HTTP 请求 3 秒之后超时,报 “TimeoutError: [Errno 110] Connection timed out”。
在我本地就按我们的定义的超时时间 5 秒超时,报 “tornado.simple_httpclient.HTTPTimeoutError: Timeout while connecting”。
#8 Go HTTP 客户端
HTTP Golang 2022-01-29原生
之前的文章:Golang HTTP 以及 HTML/XML 解析
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
fmt.Printf("%#v\n", resp.Status) // string, "200 OK"
fmt.Printf("%#v\n", resp.StatusCode) // int, 200
fmt.Printf("%#v\n", resp.Header) // http.Header, map[string][]string
fmt.Printf("%#v\n", resp.Request) // *http.Request
fmt.Printf("%#v\n", resp.ContentLength) // int64
fmt.Printf("%#v\n", resp.TransferEncoding) // []string(nil)
fmt.Printf("%#v\n", resp.Trailer) // http.Header(nil)
fmt.Printf("%#v\n", resp.Uncompressed) // bool
fmt.Printf("%#v\n", resp.TLS) // *tls.ConnectionState
fmt.Printf("%#v\n", resp.Body) // *http.bodyEOFSignal => io.ReadCloser => io.Reader
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
multipart
admin@victus:~$ cd /C/Program\ Files/Go/src/mime/multipart
nosch@victus:/C/Program Files/Go/src/mime/multipart$ grep -ER 'func.+\) [A-Z]\w+' .
./formdata.go:func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
./formdata.go:func (f *Form) RemoveAll() error {
./formdata.go:func (fh *FileHeader) Open() (File, error) {
./formdata.go:func (rc sectionReadCloser) Close() error {
./formdata_test.go:func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
./formdata_test.go:func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) {
./multipart.go:func (p *Part) FormName() string {
./multipart.go:func (p *Part) FileName() string {
./multipart.go:func (r *stickyErrorReader) Read(p []byte) (n int, _ error) {
./multipart.go:func (p *Part) Read(d []byte) (n int, err error) {
./multipart.go:func (pr partReader) Read(d []byte) (int, error) {
./multipart.go:func (p *Part) Close() error {
./multipart.go:func (r *Reader) NextPart() (*Part, error) {
./multipart.go:func (r *Reader) NextRawPart() (*Part, error) {
./multipart_test.go:func (mr *maliciousReader) Read(b []byte) (n int, err error) {
./multipart_test.go:func (s *slowReader) Read(p []byte) (int, error) {
./multipart_test.go:func (s *sentinelReader) Read([]byte) (int, error) {
./writer.go:func (w *Writer) Boundary() string {
./writer.go:func (w *Writer) SetBoundary(boundary string) error {
./writer.go:func (w *Writer) FormDataContentType() string {
./writer.go:func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
./writer.go:func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {
./writer.go:func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) {
./writer.go:func (w *Writer) WriteField(fieldname, value string) error {
./writer.go:func (w *Writer) Close() error {
./writer.go:func (p *part) Write(d []byte) (n int, err error) {
第三方库
GitHub: http client stars:>1000
- go-resty/resty
Simple HTTP and REST client library for Go - parnurzeal/gorequest
GoRequest -- Simplified HTTP client ( inspired by nodejs SuperAgent ) - gojek/heimdall
An enhanced HTTP client for Go - imroc/req
Simplified Golang HTTP client library with Black Magic, Less Code and More Efficiency - dghubble/sling
A Go HTTP client library for creating and sending API requests - hashicorp/go-retryablehttp
Retryable HTTP client in Go
简单的了解:
- resty 看起来确实不错,链式调用,清晰明了,而且有不错的调试信息。
- gorequest 是在原生库上做了一点简单的封装,优化调用体验。有篇中文文档可以参考:gorequest中文文档(非官方)
需要学习一下他的设计。官方文档说是借鉴 Node.js 的 SuperAgent。 - sling 也挺有特色的,使 API 变得结构化,调用变得像普通的 Go 函数一样。
- go-retryablehttp 在原生库上加了一个自动重试机制。
- heimdall, req, 简单一看,还看不出来有什么特别的地方。
#7 Urlencode
HTTP urlencode 2020-04-19URL / URI 的设计中规定允许的字符,如果出现了其他字符就需要转义,这套规则被称之为百分号编码(Percent-encoding)。
WWW 的设计中就使用了这套规则,比如 URL 地址、和表单提交(application/x-www-form-urlencoded)等场景,所以这个编码规则也被称之为 URL 编码(URL encoding)。
编程时,编码解码操作一般就叫 urlencode,urldecode。
编码的方式非常简单,就是把字节用 16 进制的方式表示,然后每个字节前面加一个百分号。
#6 Python 应用: 简易 HTTP 服务器
Python HTTP PythonSimpleServer 2018-05-07Python2
在当前目录起 HTTP 服务,可以用于测试和临时性的文件下载服务。
# Default bind to 0.0.0.0:8000
python -m SimpleHTTPServer
# Maybe you want to use port 8080
python -m SimpleHTTPServer 8080
Python3
除了可以指定端口,还可以指定绑定地址、工作目录。
# Also bind to 0.0.0.0:8000
python -m http.server
python -m http.server -h
# usage: server.py [-h] [--cgi] [--bind ADDRESS] [--directory DIRECTORY] [port]
#
# positional arguments:
# port Specify alternate port [default: 8000]
#
# optional arguments:
# -h, --help show this help message and exit
# --cgi Run as CGI Server
# --bind ADDRESS, -b ADDRESS
# Specify alternate bind address [default: all interfaces]
# --directory DIRECTORY, -d DIRECTORY
# Specify alternative directory [default:current directory]
python -m http.server 9999
python -m http.server --bind=127.0.0.1
python -m http.server --bind=127.0.0.1 9999
python -m http.server -d ~/Pictures
#5 HTTP 代理 [编辑中]
网络代理 HTTP 2017-06-08:) 本文正在编辑中,暂时不提供浏览...
#4 使用 wget 复制站点
Linux wget 开发工具 HTTP 2016-04-26复制指定 URL 路径下的所有文件到本地目录 HTML 下:
wget -m -p -k -np -P <HTML> <URL>
#3 HTTP Cookie
HTTP Cookie 2016-01-28Cookie 的相关知识总结