HTTP
特点
- 客户端/服务端模式,只能由客户端发送请求之后才能得到服务端响应
- 请求时只需传送请求方法和资源路径
- 可以传输任意类型的数据,类型由
Content-Type字段标记 - 默认情况下一个请求由一个连接处理,请求结束后就断开连接
- 无记忆之前的数据,需要依赖
Cookies和Session等数据存储才能实现记忆之前的数据
URI
URI(统一资源标识符),主要包括两类:
- URL(统一资源定位符):
protocol://[username:password@]host:port/path[?query#hash]protocol:使用的协议,若没有此字段顶多称为 URI 而不能称为 URLusername:password:登入的用户名和密码,一般也没有人会这样用,因为太不安全了host:port:主机和端口,主机可以是 IP 也可以是域名,域名会通过 DNS 解析成相应的 IPpath:服务器软件资源目录中的路径query:查询字符串,使用key=value的形式,多个键值对使用&分隔hash:页面片段哈希值,前端通常当作锚点定位使用
- URN(统一资源命名符):
urn:hierarchicalurn:表明是一个 URN,若没有此字段顶多称为 URN 而不能称为 URLhierarchical:该资源的层级关系,多个层级使用:分隔,比如人:男人:张三
乱码的原因
- 编码和解码使用的方式不一致
- 使用的编码方式中没有对应的字符集,即时解码方式一致也不会出现正确的结果
URL 中的百分号编码,会对不属于 ASCII 码的字符和属于 ASCII 码但是又属于保留字的字符进行百分号编码,百分号编码就是对非 ASCII 码取 Unicode 内码再加%前缀
HTTP 报文
常用请求方法
- GET:作为 URL 的一部分向服务器端发送,是浏览器默认请求方式
- 由于是 URL 的一部分,所以很容易从浏览历史记录中查到表单提交内容,不太安全
- 由于是 URL 的一部分,所以请求体就是 URL 中的 query 部分,没有显示的请求体
- URL 长度有限制
- POST:用于提交表单数据或大批量的数据
- 有自己的请求体,相对比较安全
- 没有长度限制,所以可以提交大批量数据
- PUT:用于更新数据资源
- HTTP 1.1 版本不带有 PUT 方法的验证机制,所以存在一定的安全隐患,一般不使用
- DELEAT:用于删除数据资源
- HTTP 1.1 版本不带有 DELEAT 方法的验证机制,所以存在一定的安全隐患,一般不使用
- HEAD:与 GET 请求相同,不同的是只获取响应头,而没有响应体,所以多作用与超链接弹探测
- OPTIONS:用于查询接口支持的请求什么方法
- TRACE:回显服务器收到的请求,主要用于测试和诊断,容易引起一种 XST(跨站追踪)的攻击方式,所以一般不使用
- CONNECT:开启客户端与请求资源之间的双向沟通通道,通常用于访问代理服务器
常用响应状态码
- 1 XX:临时响应,已经接受需要继续处理,没有响应体
- 2 XX:成功
200 OK:请求已成功202 Accepted:已接受,但未处理完成206 Partial Content:服务器成功处理了部分内容,多用于请求部分内容,即断点续传完成
- 3 XX:重定向
301 Moved Permanently:永久移动,URI 会变,浏览器会有缓存302 Found:临时移动,URI 不会变,浏览器不会有缓存304 Not Modified:文件未修改,使用本地缓存文件
- 4 XX:客户端请求错误
400 Bad Request:客户端语法错误401 Unauthorized:未授权的,请求要求客户身份认证403 Forbidden:拒绝访问,没有权限404 Not Found:资源未找到406 Non Acceptable:无可接收的媒体类型416 Range Not Satisfiable:请求部分资源内容范围错误
- 5 XX:服务器错误
500 Internal Server Error:服务器内部错误,无法完成请求502 Bad Gateway:网关或代理服务器错误,无效的请求
报文头
通用报文头
可以通用于请求报文头和响应报文头
| 字段名 | 描述 |
|---|---|
Cache-Control |
缓存控制 |
Connection |
逐跳首部,连接管理 |
Date |
创建报文的日期时间 |
Pragma |
报文指令 |
Trailer |
报文末端的首部 |
Transfer-Encoding |
指定报文主体的传输编码 |
Upgrade |
升级为其他协议 |
Via |
代理服务器的相关信息 |
Warning |
错误通知 |
Connection:连接管理keep-alive:网页打开请求结束后不会断开 TCP 连接,若再次发送请求还会使用该连接,HTTP 1.1 默认采用长连接close:请求结束后就会断开 TCP 连接,若再次发送请求会重新建立连接,HTTP 1.0 默认采用短连接
请求报文头
只在请求头中出现
| 字段名 | 描述 |
|---|---|
Accept |
优先媒体类型 |
Accept-Charset |
优先字符集编码 |
Accept-Encoding |
优先内容编码 |
Accept-Language |
优先自然语言 |
Authorization |
Web 认证信息 |
Expect |
期待服务器的特定行为 |
From |
用户电子邮箱地址 |
Host |
请求资源服务器地址和端口号 |
If-Match |
比较实体标记(ETag) |
If-None-Match |
比较实体标记 |
If-Modified-Since |
比较资源更新时间 |
If-Unmodified-Since |
比较资源的更新时间 |
If-Range |
资源未更新时发送实体 Byte 的范围请求 |
Max-Forwards |
最大传输逐跳数 |
Proxy-Authorization |
代理服务器要求客户端的认证信息 |
Range |
实体的字节范围请求 |
Referer |
对请求中 URI 的原始获取放 |
TE |
传输编码优先级 |
User-Agent |
HTTP 客户端程序信息 |
Host:请求资源服务器地址和端口号,是直接从 URL 中截取出来的,可能是 IP 也可能是域名Referer:告知服务器是从那个连接中跳过来的User-Agent:客户端使用的操作系统、浏览器名称和版本信息
响应报文头
只在响应头中出现
| 字段名 | 描述 |
|---|---|
Accept-Ranges |
是否接受字节范围请求 |
Age |
推算资源创建经过时间 |
ETag |
资源的匹配信息 |
Location |
令客户端重定向到指定的 URI |
Proxy-Authenticate |
代理服务器对客户端的认证信息 |
Retry-After |
对再次发起请求的时机要求 |
Server |
HTTP 服务器的安装信息 |
Vary |
代理服务器缓存的管理信息 |
WWW-Authenticate |
服务器对客户端的认证信息 |
实体报文头
用来描述实体
| 字段名 | 描述 |
|---|---|
Allow |
资源可支持的 HTTP 方法 |
Content-Encoding |
实体主体使用的编码方式 |
Content-Language |
实体主体的自然语言 |
Content-Length |
实体主体的大小,以字节为单位 |
Content-Location |
其实是代替对应资源的 URI |
Content-MD5 |
实体主体的报文摘要 |
Content-Range |
实体主体的位置访问 |
Content-Type |
实体主体的媒体类型 |
Expires |
实体主体的过期的日期时间 |
Last-Modified |
资源的最后修改日期时间 |
CORS 跨域请求
需要浏览器和服务器都支持,目前所有浏览器都支持,整个 CORS 通信过程,浏览器都是自动完成的,浏览器一旦发现 AJAX 请求跨域,就会自动附加一些头部信息,所以实现 CORS 通信的关机是服务器
简单请求
简单的说简单请求就是简单的请求方法和简单的请求头的结合,表单请求也是简单请求,表单请求在历史上是一直可以跨域请求的
-
请求方法是:
HEAD、GET、POST -
请求头只有:
AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:仅限三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
简单请求流程
浏览器直接发出 CORS 请求,在请求头中添加一个 Origin 字段来标明本次请求来自哪个域(协议+域名+端口)
- 若该域不在许可范围内,服务器会返回一个正常的 HTTP 响应,这个正常的响应中没有包含
Access-Control-Allow-Origin字段,所以浏览器就会忽略掉接收请求,就会抛出一个错误被XMLHttpRequest的onerror回调函数捕获,这种错误是无法使用状态码来判断的,因为是一个正常的 HTTP响应 - 若该域在许可范围内,服务器就会在响应头中添加以下三个字段
Access-Control-Allow-Origin:该字段是必须的,要么是*表示可接受任意域请求,要么与请求时的Origin的值相同(要注意域名和 IP 的映射关系浏览器是不知道的,所以也属于不同域,而且只能设置一个值,若想设置多个就需要在程序中实现)Access-Control-Allow-Credentials:该字段可选,它的值是一个布尔值,表示是否允许浏览器发送 Cookie,默认不发送(不设置就相当于 false),只能设置为 true;若只是将XMLHttpRequest的withCredentials设置为 true,但是服务器不允许发送 Cookie,则浏览器不会将响应内容返回给请求者,只有两者同时为 true 才行;设置上传 Cookie 后Access-Control-Allow-Origin字段就不能使用*,必须与请求网页同域,Cookie 依然遵循同源政策,也就是上传是 AJAX 请求域的 Cookie 而不是当前页面的 Cookie,当前页面也无法拿到 AJAX 请求域的CookieAccess-Control-Expose-Headers:该字段可选,在 CORS 请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到 6 个服务器返回的基本字段,若想使用该方法拿到其他的字段(包括自定义字段)就需要在该字段指定;6 个基本字段包括:``Cache-Control、Content-Language、Content-Type、Expires、Last-Modified和Pragma`
非简单请求
非简单请求的 CORS 请求,会在正式通信前增加一次 HTTP 查询请求,询问服务器当前页面域名是否在服务器允许跨域白名单中,以及可以使用哪些 HTTP 方法和请求头字段,只有得到肯定的答复,浏览器才会发出正式的 AJAX 请求,否则就会报错
比如:请求方法是 PUT 或 DELETE,Content-Type 字段的类型是 application/json
1. 预检请求
- 预检请求使用的是
OPTIONS方法 - 主要有这几个字段来进行询问
Origin:标明请求来自哪个域Access-Control-Request-Method:要使用的请求方法Access-Control-Request-Headers:要使用哪些自定义请求头字段,多个可使用逗号分隔
2. 预检请求响应
- 主要有对应的字段来进行响应
Access-Control-Allow-Origin:允许跨域的域Access-Control-Allow-Methods:允许使用的请求方法,多个用逗号分隔Access-Control-Allow-Headers:允许使用的自定义请求头字段,多个用逗号分隔Access-Control-Allow-Credentials:是否需要发送 Cookie,与简单请求中的一致Access-Control-Max-Age:指定多久之内不需要在发送预检请求,以秒为单位
- 允许:上述的字段的值都应该大于等于(预检请求的值都包含在预检响应中)请求允许
- 不允许:返回一个正常的 HTTP 响应,但是没有任何 CORS 相关字段或者明确表示请求不符合条件,这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被
XMLHttpRequest对象的onerror回调函数捕获
3. 浏览器的正常请求和响应
一旦预检请求通过后,就都跟简单请求一样,请求头会增加一个 Origin 头信息字段,响应体会增加一个 Access-Control-Allow-Origin 字段
HTTP 缓存
Cache-Control:缓存控制no-store:所有内容都不缓存no-cache:缓存,但是缓存前会判断缓存资源是否是最新no-transform:代理服务器无法修改缓存内容,只是声明性的max-age=x:请求缓存缓存后 x 秒内不再发起请求,与Expires类似,是 HTTP1.1的属性,与Expires共存的情况下优先级高于Expiress-maxage=x:代理服务器请求源站点缓存后 x 秒内不再发起请求max-stale=x:即使缓存已经过期了,但是在 x 秒内可以使用过期缓存public:客户端和代理服务器都可以缓存private:只能客户端可以缓存,只是声明性的
原理
使用 Cache-Control 字段即可启动缓存机制,详细的缓存控制在上面通用报文头中
max-age=x:请求缓存缓存后 x 秒内不再发起请求,与Expires类似,是 HTTP1.1的属性,与Expires共存的情况下优先级高于ExpiresExpires:实体主体的过期的日期时间,与缓存控制中的max-age=x类似,是 HTTP 1.0 的字段,与max-age=x共存的情况下,优先级低于max-age=xIf-Modified-Since:比较资源更新时间,最短时间是以秒为单位的,由于在请求头中出现,所以是客户端告诉服务器,与响应头中的Last-Modified是一对Last-Modified:资源的最后修改日期时间,最短时间是以秒为单位的,由于在响应头中出现,所以是服务器告诉客户端,与If-Modified-Since是一对ETag资源的匹配信息,由文件内容生成,解决了以秒为单位的长时间限制,与If-None-Match是一对If-None-Match比较实体标记,由文件内容生成,解决了以秒为单位的长时间限制,与ETag是一对
使用缓存的流程
- 开启缓存,先由过期时间起到作用,在一定时间内使用本地缓存,要注意
Expires的优先级低于max-age=x,也就是说共存情况下Expires将无效 - 再由资源文件的标记信息起作用,也就是说同时设置了
Last-Modified和ETag,Last-Modified将无效 - 若未设置
ETag文件标记,则才会使用Last-Modified对比文件是否修改
由步骤可知道,缓存的问题就是服务器更新,这些更新条件都是在文件过期的情况下对比文件是否跟新,为了解决这个问题,需要采用 md 5/hash 值对静态资源文件进行唯一标识名,当服务器更新时,文件的名字就会更改,名字更改了就不会在使用缓存
浏览器操作对缓存的影响
| 用户操作 | 过期时间 | 文件对比 |
|---|---|---|
| 地址栏回车 | 有效 | 有效 |
| 页面连接跳转 | 有效 | 有效 |
| 新打开窗口 | 有效 | 有效 |
| 前进后退 | 有效 | 有效 |
| F 5 刷新 | 无效 | 有效 |
| Ctrl+F 5 强制刷新 | 无效 | 无效 |
内容协商
原理
| 请求头 | 描述 | 响应头 |
|---|---|---|
Accept |
媒体类型 | Content-Type |
Accept-Charset |
字符集 | Content-Type |
Accept-Encoding |
编码 | Content-Encoding |
Accept-Language |
自然语言 | Content-Language |
要知道这些字段的值,若是多个,后面的会覆盖掉前面的;为了有多个值,就需要使用 q=x 权重的概念,该权重值的范围是[0,1]之间的数字,数值越大权重越高;多个值是由逗号分隔的,为了为值增加权重的概念,权重和值使用分号进行分隔
Accept:客户端可接受的媒体类型,若服务端无法匹配则会返回 406 错误*/*:全部可接受
Accept-Charset:客户端接受的字符集类型utf-8:也可是其他类型字符集
Content-Type:服务端返回的实体主体的媒体类型,是 MIME 格式的类型;使用分号分隔字符集text/html:HTML 格式text/plain:纯文本格式text/xml:XML 格式image/gif:gif 图片格式image/jpeg:jpg 和 jpeg 图片格式image/png:png 图片格式application/xhtml+xml:XHTML 格式application/xml:XML 数据格式application/atom+xml:Atom XML 聚合格式application/json:JSON 数据格式application/pdf:pdf 格式application/msword:Word 文档格式application/octet-stream: 二进制流数据(如常见的文件下载)application/x-www-form-urlencoded:表单默认的提交数据的格式
Accept-Encoding:客户端可接受的压缩方式*:任意压缩格式gzip:gzip 压缩格式deflate:deflate 压缩格式
Content-Encoding:服务端返回主体内容的压缩方式gzip:gzip 压缩格式deflate:deflate 压缩格式
Accept-Language:客户端可接受的自然语音类型zh-cn:中国大陆zh:中文en:英语en-us:英语美国
Content-Language:服务端返回主体内容的自然语言类型zh-cn:中国大陆zh:中文en:英语en-us:英语美国
协商方式
- 客户端驱动:客户端发起请求,服务端发送可选项列表,客户端做出选择后发送第二次请求
- 服务端驱动:服务端检查客户端的请求头并决定提供那个版本的页面,当都不匹配时服务器会返回默认版本的页面
- 透明协商:由缓存代理服务器来代表客户端进行协商,是非 HTTP 协议标准 M,但是效率比较高
断点续传与多线程下载
原理
-
请求头中增加字段
Range来指定请求资源的片段,该字段的值有以下几种形式bytes=0-99:请求 0 到 99 字节内容bytes=-99:请求最后 99 个字节内容bytes=99-:请求从第 99 到最后的内容bytes=0-29,50-99:请求从 0 到 29 和 50 到 99 字节两部分的片段
-
响应头中增加字段
Content-Range来指定返回资源的片段,该字段的值与Range类似,只不过多增加了一个总大小,格式如下bytes=99-/1024:返回从 99 字节到最后的内容,总大小为 1024 字节
断点续传和多线程下载的过程
断点续传是客户端主动的分片传输,而多线程是服务端主动的分片传输,原理是一致的,这里只说明断点续传
- 客户端请求下载一个 1024 字节大小的文件,已经下载了 512 字节
- 网络中断,客户端请求断点续传,在请求头中声明本次断点续传的起点,即
Range: bytes=512- - 服务端收到断点续传的请求,从文件的 512 字节部分开始传输,在响应头中声明断点续传的位置,即
Content-Range: bytes=512-/1024 - 并且返回的 HTTP 状态码是 206 表示断点续传成功,而不是 200
认证方式
Basic 认证方式
- 客户端先发送请求,服务端返回 401 状态码要求用户身份认证,同时返回一个
WWW-Authenticate响应头信息 - 用户填写用户名和密码后,浏览器会自动将用户名和密码字符串使用冒号连接后,采用 base 64 编码,放在请求头的
Authenticate字段中(该字段值的前面还需要添加 Basic 空格前缀)发送给服务器 - 认证通过后返回 200 状态码,失败后继续返回 401
Digest 认证方式
- 客户端先发送请求,服务端返回 401 状态码要求用户身份认证,同时返回一个
WWW-Authenticate响应头信息,该信息中会包含一个临时质询码(就是一个随机的字符串) - 用户填写用户名和密码后,浏览器会自动将用户名和密码字符串使用冒号连接后,使用临时质询码再 base 64 编码,放在请求头的
Authenticate字段中(该字段值的前面还需要添加 Digest 空格前缀,和临时质询码以及必要的一些信息)发送给服务器 - 认证通过后返回 200 状态码,失败后继续返回 401
SSL 客户端认证方式
- 客户端先发送请求,服务端会要求用户进行身份认证,该认证是通过表单认证,同时服务端会要求下载客户端证书
- 每次登入时都会将该证书以 HTTP 报文的方式发给服务器
- 验证通过后,就可以领取证书内的公开密钥,之后就可以开始 HTTPS 加密通信
FormBase 认证方式
就是通过 Cookie 和 Session 的认证方式
Cookie 与 Session
- Cookie:
- 是一段文本信息,用来保存用户信息,主流浏览器对是以文本文件形式保存在本地
- 客户端请求服务器时会自动将 Cookie 在请求头中作为一个字段发送,服务端需要在响应头中使用 Set-Cookie 设置带回的 Cookie
- Session:
- Session 也是用来保存用户的信息,保存在服务端,通常需要借助于 Cookie 来存储一个 SessionID 来保存用户的登入状态
- 由于保存在服务端,通常都在内存中,必然会消耗大量的服务端资源,所以为了节省服务器资源就会将一些不活跃的 Session 删除掉
- 虽然最常用的是使用 Cookie 来存储 SessionID,但是在用户禁用 Cookie 时会无法使用,也可以采用其他方式,比如:
- URL 重写:在 URL 中的 query 部分增加查询 SessionID 的字段
- 隐藏表单:使用隐藏表单保存 SessionID

Comments NOTHING