网工笔记(五):HTTP协议

本文介绍了HTTP协议的基本概念,包括其版本变迁、状态码、头标的作用、HTTPS安全、认证机制、Cookie、WebHook和WebSocket以及CORS问题。适合开发人员和网工了解和解决HTTP相关问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HTTP是一个网络7层协议,需为网络协议,做网工的同学却不常接触,做开发的同学反倒更多地使用到它。 在调试HTTP问题时,往往出现一个尴尬的局面,开发的同学认为那是网络的问题,而网工同学却认为是应用程序上的问题。这篇文章给HTTP及相关网页技术做一个入门介绍,希望尽可能地照顾到HTTP开发及调试中可能需要的知识点,感兴趣的读者可以根据这些知识点关键字去搜索去问AI做进一步的研究。

HTTP是一个C/S架构的协议,C/S就是客户端/服务器,它由客户端发出HTTP请求,然后服务器作出HTTP回复。在网页环境中,客户端一般指的就是浏览器,但也可以是任何能发出HTTP请求的工具及环境。在下文中提到的请求,一般指HTTP请求,与客户端相关;回复指的就是HTTP回复,与服务器端相关。以下是本文的提纲。

  • HTTP的版本
  • HTTP状态码 200,404,502
  • HTTP头标 (HTTP Header)
  • HTTPS
  • HTTP认证(HTTP Authentication)
  • HTTP Cookie
  • Web Hook和Web Scoket
  • CORS问题

HTTP的版本

HTTP版本有三种,分别为HTTP1,HTTP2和HTTP3(UQIC)。现在我们看到的HTTP1,大多为HTTP1.1这个版本。HTTP2在HTTP1.1的基础上又提出了不少改进,以下是几个在HTTP2中比较大的改进。

  • 多路复用(Multiplexing):在HTTP1.0,每个HTTP请求都要单独生成一个TCP连接,这个做法比较慢也耗资源。 在HTTP1.1引入了presistent conection这个机制,让相关的多个请求可以重用同一个TCP连接 。到了HTTP2,在同一个TCP连接中可以并行发送多个HTTP请求,这解决了“队头阻塞”(Head-of-Line Blocking)的问题,即头部中一个请求延迟导致所有后续请求都被延迟的问题。
  • 二进制协议(Binary Protocol):HTTP1是文本协议,头部和内容都是以明文形式传输。HTTP2使用二进制格式传输数据,这使得协议更加紧凑且高效。
  • 服务器推送(Server Push)HTTP1 中客户端需要请求特定资源才能获取,服务器端无法主动推送。HTTP2 服务器可以在客户端请求之前主动将资源推送到客户端,这也提高了时效性。

对于HTTP2,目前主流浏览器(如Chrome, Firefox)都要求HTTP2使用加密的传输方式。值得一提的是这是浏览器开发商的要求,并非HTTP2协议的要求。想查看一个网站是否支持使用HTTP2,可以使用如下 curl命令。

$ curl -I --http2 https://example.com
HTTP/2 200

HTTP3在2022年才被正式发布在RFC上,但实际上已经有一定数量的应用在使用这个协议。它的最特别之处就是使用了UQIC作为传输层协议(HTTP1和HTTP2用的都是TCP),而QUIC是一个基于UDP的协议。。。你一定会问这不会有数据丢失的问题吗?QUIC的名字来源于Quick UDP Internet Connections的首字母组合,正与其英文中的含义它希望使用UDP的快,它使用了多路的UDP连接来实现类似TCP的机制达到确保数据完整性的目的。

HTTP状态码 (HTTP Response Code)

HTTP状态码,英文为http status code或作http response code。H TTP回复中总会有这个状态码,让HTTP的请求方能直观地知道这个请求是否成功,或存在什么问题。常见的状态码主要有这3种类型: 200,400和500。如果你的请求得到的代码是4XX或者5XX这种形式,意味着有错误发生,理解状态码的含义在开发debug中很重要。 

  • 200类型:这个类型指的就是在200到299之间的这些状态码,如果你得到的是200开头的状态码,基本上就是你的请求已被服务器端接受了,没有什么问题。
  • 400类型:在400到499之间的状态码,代表错误可能在客户端。这里说的客户也指的是请求端。
  • 500类型:在500到599之间的状态码,代表错误可能发生在服务器端。

值得指出的是400类型代码所谓的客户端问题有时并非真的错误就发生在客户端上。最常见的例子为404这个错误代码,404指的是客户端尝试访问不存在的资源,但这个错误的原因往往是因为服务器端给客户提供了错误的URL链接。

以下是一些常见的HTTP状态码:

200请求已成功
401请求未认证
403请求不被允许 (例如请求企图删除重要资源)
404请求的资源未被发现
500服务器内部问题
502代理器接受了请求,但代理器的后端没有回应 (这个错误代码常在均衡器上出现)
503服务器当前无法处理请求

HTTP 头标 (HTTP Header)

HTTP回复中一般包含三个部分:HTTP状态码,HTTP头标和HTTP正文;HTTP头标在协议中扮演着重要的角色,它为HTTP提供了元数据。随着micro services架构的推广,我们经常能看HTTP的回复正文中用的数据是JSON而不是HTML,对于客户端如何知晓HTTP回复中的数据格式是JSON还是 HTML呢?答案就是通过HTTP头标,用HTTP头标 'Content-Type: application/json' , HTTP接收方就知道这是JSON的数据。 我们知道的HTTP cookie, HTTP授权 (authorization)也都是HTTP头标的一种。我们可以用 curl 命令中 -I 这个参数来看看一个HTTP回复中用了那些头标。

$ curl -I --http2 https://www.example.com
HTTP/2 200
content-encoding: gzip
accept-ranges: bytes
age: 443844
cache-control: max-age=604800
content-type: text/html; charset=UTF-8
date: Wed, 10 Nov 2023 11:43:30 GMT
etag: "3147526947"
expires: Wed, 29 Nov 2023 11:43:30 GMT
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
server: ECS (nyb/1D2E)
x-cache: HIT
content-length: 648

在下文中我们还会讲到其它的头标。这里我们先看看两个中比较常见的头标:1 User-Agent 和 2. Host。

User-Agent 这个头标常用于为服务器提供用户的一些环境信息。最常见的用例就是在发HTTP请求时把用户的设备信息放在User-Agent中来,服务器就能通过这个信息知道用户使用的是Android 还是苹果的设备,从而提供更匹配的应用版本。

Host 这个头标用于指明目标服务器的域名。在很多应用或网站的部署中会使用同一个IP地址支持多个不同的服务,Host这个头标可用于指明该请求希望使用的服务。 对于不匹配的服务或域名,服务器即可拒绝执行请求。

以下是一个CURL测试,首先我用nslookup找到了example.com对应的IP地址,然后看看使用不同Host头标作请求时的情况。以下分别为使用头标Host: example.comHost:google.com头标的输出。可以看到使用Host:google.com会得到404错误状态码,因为那个IP是对应 example.com这个域名的。

$ curl -I -H 'Host: example.com' 93.184.216.34
HTTP/1.1 200 OK

$ curl -I -H 'Host: google.com' 93.184.216.34
HTTP/1.1 404 Not Found

HTTPS

对于需要确保信息安全的HTTP连接,我们使用HTTPS,即加密的HTTP。TLS(Transport Layer Security)是现在主流的加密协议,它的加密发生在传输层上,所以HTTP头标,HTTP正文和HTTP状态码都会被保护起来,非客户端和服务器端都不能看到HTTP的任何内容。这也是为什么我们可以把HTTP的验证和HTTP Cookie这些可能包含敏感信息的数据放在头标上。

TLS是现时主要的加密协议,它的前身是SSL(Secure Sockets Layer)。理论上 SSL应该在2015后就被停止使用 (deprecated),但江湖上依然流传着它的传说。 TLS1.0和TLS1.1版本也在2021时被RFC提出停止使用,预期主流的加密协议将会是TLS1.2 和TLS1.3 。

提到加密协议就不得不提证书这个概念。HTTP加密连接一般是由服务器端给客户端提供一个公开密钥,客户端即可使用该密钥加密数据,并只有持有私有密钥的服务器端可以解码。这个证书就是为了用来验证这个公开密钥的可信性的。一个TLS或SSL证书会包含以下几个内容:

  • 域名:就是提供HTTPS连接的这个网站的域名。
  • 公开密钥: 用于对HTTP内容进行加密的密钥。
  • CA (Certificate authority):一个权威或具有公信力的机构,对提供证书的网站进行验证。CA会提供一份自己的证书,与网站自身提供的证书成为一个证书链。对于自身就有公信力的网站,它们可以把自己作为CA,这种证书就称为self-signed certificate。
  • CA提供的签名:CA会用私有密钥对网站证书进行签名,在CA证书中有CA的公开密钥,收到证书的用户就可以用CA的密钥对该签名进行解码验证。

想要查看一个网站的证书有两种办法,你可以使用的你的浏览器提供的功能去查看,这里就不展示了。另一个方法就是使用命令行, openssl这个工具。以下是一个测试的例子,由于输出太多我只截取了部分内容。

$ openssl s_client -connect google.com:443
CONNECTED(00000006)
depth=0 OU = "No SNI provided; please fix your client.", CN = invalid2.invalid
verify error:num=18:self signed certificate
verify return:1

Server certificate
-----BEGIN CERTIFICATE-----
MIIDfDCCAmSgAwIBAgIJAJB2iRjpM5OgMA0GCSqGSIb3DQEBCwUAME4xMTAvBgNV
BAsMKE5vIFNOSSBwcm92aWRlZDsgcGxlYXNlIGZpeCB5b3VyIGNsaWVudC4xGTAX
...
...
gWbFcmkgBLYpE8iDWT3Kdluo1+6PHaDaLg2SacOY6Go=
-----END CERTIFICATE-----

New, TLSv1/SSLv3, Cipher is AEAD-AES256-GCM-SHA384

HTTP基本认证 (HTTP Authorization and Authentication)

当你登陆一个网站时你需要在页面输入用户名和密码来认证登陆,后续的HTTP请求就不用再认证了。服务器端是如何去保证你的请求都是你的请求呢?做法有两种,一种是使用cookie, 一种就是使用HTTP Authorization头标。这里我们先说HTTP Authorization。值得注意的是英文Authorization的意思是授权,认证的英文是Authentication。但HTTP中并没有HTTP Authentication这个头标,HTTP Authorization就被用做认证。使用HTTP头标作认证有两种比较常见的认证方式。

  • 基本认证: 头标通常写成如下形式 Authorization: Basic <base64 code>。这里basic是关键词告知服务器这是基本认证,<base64 code>是对用户名和密码用base64计算后得到的编码。以下是一个使用python获得base64编码后,使用基本认证头标的例子。
$ python -c 'import base64; print(base64.b64encode(b"username:password"))'
dXNlcm5hbWU6cGFzc3dvcmQ=
$
$ curl -I -H 'Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ' example.com
HTTP/1.1 200 OK
  • 令牌(token)认证: 头标通常写成如下形式 Authorization: Bearer <JWT token>。这里Bearer是关键词告知服务器使用令牌,<JWT token> 就是JWT令牌,通常为一段较长的base64编码。JWT 令牌一般在首次登陆时由服务器生成并返回给客户端,客户端会有对应的代码(如javascript)把它保存在客户端浏览器的本地存储(local storage)上或会话存储(session storage)上。

由于身份认证数据较为敏感,所以不论是使用JWT令牌或Cookie,在存储认证数据(JWT令牌或Cookie)到浏览器端时,网站都会给它设定有效时间,一段时间后就会自动删除或失效。最后提一下,使用HTTP认证时一定要用HTTPS,它会对所有的HTTP的内容包括头标进行加密。

HTTP Cookie

前文已经提到了Cookie,由于它这个特别的名字,很多非技术人员知道网页中有cookie这么一个东西。Cookie是一种存储于客户浏览器端的数据,它给HTTP提供了缓存会话(session)状态的能力。这个说法可能有点抽象,我们来看看前文中的例子,大多数网站都只需要你在首次登陆时输入密码,后续的HTTP请求就不用再认证了。这是如何做到的?使用Cookie可以把用户与服务器的会话认证信息存储在客户端,每次发送请求时认证信息会作为cookie被一并发送到服务器端,服务器即可认证该会话(session)。

看到这里你可能会问本地存储(local storage),会话存储(session storage)和cookie都可以在浏览器上存储数据,那它们的区别在哪?Cookie跟另外两个存储的区别在于它是头标,一旦生成后在后续的每次HTTP请求中都会被发送。

Cookie中的令一个常见用途就是存储客户偏好,例如一个网站它提供了中文和英语两种页面,当客户选择了使用中文后这个偏好就可以存储在Cookie上,客户就不需要每次都选择。你可能会问为什么不能存在服务器端呢?把这些偏好信息存在服务器上会给存储带来压力。大多数网站的架构都是服务器集群加均衡器的模式,这些服务器集群可能分布到不同国家或地区,把这些客户偏好信息放在服务器端即要求这些信息要在这些集群的存储器间进行同步。相对而言,把这些非关键信息存在客户端会是更好的做法。

Web Hook和Web Scoket

这里我们再讲两个在网站中常用的技术 -- Web Hook和Web Scoket。它们通常用于需要提供实时消息或实时通信(如聊天窗口)的网站上。

Web Hook:是一种网页通知技术。客户端登入一个网页后,只要不关闭页面,服务器端就可以通过Web Hook技术向客户在后续的时间推送通知。

Web Socket:是一种让客户端和服务器端在网页上进行双向通信的协议。要说明Web Socket不是HTTP协议的一部分。它使用HTTP(或HTTPS)实现建立连接时的握手,一旦握手成功,就会转成使用自己的协议。在HTTP握手时,HTTP状态码101会被返回,以告知通信方要变更协议(upgrading protocol)。

CORS问题

CORS (Cross Origin Resource Sharing)问题,  这是一个做前端后端开发的同学都可能碰到过的问题。这是浏览器中带有的一个安全性能,浏览器会阻止客户端向跨域名的服务器发送HTTP请求,并返回错误,目的是防止跨站脚本攻击(XSS)。

什么是XSS攻击,这就不细说了,我们只说明什么是CORS问题。在开发中一个最常见的例子就是你在本机上开发了一个前端,部署在http://localhost:80上,然后把后端部署在http://localhost:8000上,这时你在浏览器上通过前端向后端发送请求,你就会碰上CORS错误,因为你的浏览器认为http://localhost:80http://localhost:8000不是同一个域名,对,端口不同也不行。简而言之,跨域名就是你前端的域名和后端的域名不一样,那么从前端发出的请求就会被浏览器阻止,譬如说你不能从阿里的网页把请求发送去你的银行。这里说明一下,CORS防范不是HTTP协议中原有的要求,是各大流浏览器的要求。

尽管CORS防范是浏览器方面执行的,解决方法却在服务器端,就是给HTTP回复加一个头标,Access-Control-Allow-Origin: <origin domain>。这里original domain就是发送请求时的域名,如上述例子中,后端的HTTP回复中需要的头标就是Access-Control-Allow-Origin: http://localhost:80。做后端开发的同学一般需要在代码中引入相应的package去给HTTP回复加上相应的头标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值