基础概念
请求和响应报文
客户端发送一个请求报文给服务器,服务器根据请求报文中的信息进行处理,并将处理结果放入响应报文中返回给客户端。
请求报文结构:
- 第一行是包含了请求方法、URL、协议版本;
- 接下来的多行都是请求首部Header,每个首部都有一个首部名称,以及对应的值;
- 一个空行用来分隔首部和内容主体Body
最后是请求的内容主体
1 | GET http://www.example.com/ HTTP/1.1 |
响应报文结构:
- 第一行包含协议版本、状态码以及描述,最常见的是200 OK 表示请求成功
- 接下来多行也是首部内容
- 一个空行分隔首部和内容主体
- 最后是响应的内容主体
1 | HTTP/1.1 200 OK |
URL
HTTP使用URL(统一资源定位符)来定位资源,它是URI(统一资源标识符)的子集,URL在URI的基础上增加了定位能力。URI除了包含URL,还包含URN(统一资源名称),它只是用来定义一个资源的名称,并不具备定位该资源的能力 。
HTTP方法
客户端发送的请求报文第一行为请求行,包含了方法字段。
- GET:获取资源,当前网络请求中,绝大部分使用的是GET方法
- HEAD:获取报文首部,和GET方法类似,但是不返回报文实体主体部分。主要用于确认URL的有效性以及资源更新的日期时间等。
- POST:传输实体主体,主要用来传输数据,而GET主要用来获取资源。
- PUT:上传文件,由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
- PATCH:对资源进行部分修改:PUT也可以用于修改资源,但是只能完全代替原始资源,PATCH允许部分修改。
- DELETE:删除文件,与PUT功能相反,并且同样不带验证机制。
- OPTIONS:查询支持的方法,查询指定的URL能够支持的方法。会返回Allow:GET、POST、HEAD、OPTIONS这样的内容。
- CONNECT:要求在与代理服务器通信时建立隧道,使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经过网络隧道传输。
- TRACE:追踪路径,服务器会将通信路径返回给客户端。发送请求时,在Max-Forwards首部字段中填入数值,每经过一个服务器就会减1,当数值为0时就停止传输。通常不会使用TRACE,并且它容易受到XST攻击。
HTTP状态码
服务器返回响应报文中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
状态码 | 类别 | 含义 |
---|---|---|
1XX | 信息性状态码 | 接受的请求正在处理 |
2XX | 成功状态码 | 请求正常处理完毕 |
3XX | 重定向状态码 | 需要进行附加操作以完成请求 |
4XX | 客户端错误状态码 | 服务器无法处理请求 |
5XX | 服务器错误状态码 | 服务器处理请求出错 |
1XX 信息
- 100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
2XX 成功
- 200 OK
- 204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
- 206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
3XX 重定向
- 301 Moved Permanently :永久性重定向
- 302 Found :临时性重定向
- 303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
- 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
- 304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
- 307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
4XX 客户端错误
- 400 Bad Request :请求报文中存在语法错误。
- 401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
- 403 Forbidden :请求被拒绝。
- 404 Not Found
5XX 服务端错误
- 500 Internal Server Error :服务器正在执行请求时发生错误。
- 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。
HTTP首部
有四种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
具体应用
连接管理
短连接与长连接
当浏览器访问一个包含多张图片的HTML页面时,除了请求访问的HTML页面资源,还会请求图片资源。如果每进行一次HTTP通信就要新建一个TCP连接,那么开销会很大。
长连接只需要建立一次TCP连接就能进行多次HTTP通信。
- 从HTTP/1.1开始默认是长连接,如果要断开连接,需要由客户端或者服务器提出断开,使用Connection:close;
- 在HTTP/1.1之前默认是短连接的,如果需要使用长连接,则使用Connection:Keep-Alive。
流水线
默认情况下,HTTP请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于受到网络延迟和带宽限制,在下一个请求被发送到服务器之前,可能需要等待很长的时间。
流水线是在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。
Cookie
HTTP协议是无状态的,主要是为了让HTTP协议尽可能简单,使得它能够处理大量事务。HTTP/1.1引入Cookie来保存状态信息。
Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带Cookie数据,因此会带来额外的性能开销。
Cookie曾一度用于客户端数据的存储,因为当时并没有其他合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。新的浏览器API已经允许开发者直接将数据存储到本地,如使用Web storage API或IndexedDB。
用途
- 会话状态管理(如用户登录状态、购物车、游戏分数或其他需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
创建过程
服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。
客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。
分类
- 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
- 持久性 Cookie:指定过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。
Session
除了可以将用户信息通过Cookie存储在用户浏览器中,也可以利用Session存储在服务器端,存储在服务器端的信息更加安全。
Session可以存储在服务器上的文件、数据库或者内存中。也可以将Session存储在Redis这种内存型数据库中,效率会更高。
使用Session维护用户登录状态的过程如下:
- 用户进行登录时,用户提交包含用户名和密码的表单,放入HTTP请求报文中;
- 服务器验证该用户名和密码,如果正确则把用户信息存储到Redis中,它在Redis中的key称为SessionID;
- 服务器返回的响应报文的Set-Cookie首部字段包含了这个SessionID,客户端收到响应报文后将该Cookie值存入浏览器中;
- 客户端之后对同一个服务器进行请求时会包含该Cookie值,服务器收到之后提取出SessionID,从Redis中取出用户信息,继续之前的业务操作。
应该注意SessionID的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的SessionID值。此外,还需要经常重新生成SessionID。在对安全性要求极高的场景下,例如转账等操作,除了使用Session管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证等方式。
浏览器禁用Cookie
此时无法使用Cookie来保存用户信息,只能使用Session。除此之外,不能再将SessionID存放到Cookie中,而是使用URL重写技术,将SessionID作为URL的参数进行传递。
Cookie和Session选择
- Cookie只能存储ASCII码字符串,而Session可以存储任何类型的数据,因此在考虑数据复杂性时首选Session;
- Cookie存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在Cookie中,则可以将Cookie值进行加密,然后在服务器进行解密。
- 对于大型网站,如果用户所有的信息都存储在Session中,那么开销是非常大的,因此不建议将所有的用户信息都存储到Session中。
HTTPS
HTTP有以下安全性问题:
- 使用明文进行通信,内容可能会被窃听;
- 不验证通信方的身份,通信方的身份有可能遭遇伪装;
- 无法证明报文的完整性,报文有可能遭篡改。
HTTPS并不是新的协议,而是让HTTP先和SSL通信,再由SSL和TCP通信,也就是说HTTPS使用了隧道进行通信。
通过使用SSL,HTTPS具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
加密
对称密钥加密
对称密钥加密,加密和解密使用同一密钥。
- 优点:运算速度快;
- 缺点:无法安全地将密钥传输给通信方。
非对称密钥加密
非对称密钥加密,又称公开密钥加密,加密和解密使用不同的密钥。
公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。
非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送发的公开密钥对签名进行解密,就能判断这个签名是否正确。
- 优点:可以更安全地将公开密钥传输给通信发送方;
- 缺点:运算速度慢。
HTTPS采用的加密方式
上面提到对称密钥加密方式的传输效率更高,但是无法安全地将密钥传输给通信方。而非对称加密方式可以保证传输的安全性,因此我们可以利用非对称密钥加密方式将传输给通信方。HTTPS采用混合的加密机制,正是利用了上面提到的方案:
- 使用非对称密钥加密方式,传输对称密钥加密方式所需要的Secret Key,从而保证安全性;
- 获得到Secret Key后,再使用对称密钥加密方式进行通信,从而保证效率。
认证
通过使用证书来对通信方进行认证。
数字证书认证机构(CA)是客户端与服务器双方都可信赖的第三方机构。
服务器的运营人员向CA提出公开密钥的申请,CA在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将公开密钥放入公开密钥证书后绑定在一起。
进行HTTPS通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。
完整性保护
SSL提供报文摘要功能来进行完整性保护。
HTTP也提供了MD5报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算MD5的值,通信接收方是无法意识到发生了篡改。
HTTPS的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。是想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获得明文。
HTTPS的缺点
- 因为需要进行加密解密等过程,因此速度会更慢;
- 需要支付证书授权的高额费用。
GET和POST比较
作用
GET 用于获取资源,而 POST 用于传输实体主体。
参数
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。
因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 中文
会转换为 %E4%B8%AD%E6%96%87
,而空格会转换为 %20
。POST 参数支持标准字符集。
安全
安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。
GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
安全的方法除了 GET 之外还有:HEAD、OPTIONS。
不安全的方法除了 POST 之外还有 PUT、DELETE。
幂等性
幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。
所有的安全方法也都是幂等的。
在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。
GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的
POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录
DELETE /idX/delete HTTP/1.1 是幂等的,即使不同的请求接收到的状态码不一样