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:hierarchical
urn
:表明是一个URN,若没有此字段顶多称为URN而不能称为URLhierarchical
:该资源的层级关系,多个层级使用:
分隔,比如人:男人:张三
乱码的原因
- 编码和解码使用的方式不一致
- 使用的编码方式中没有对应的字符集,即时解码方式一致也不会出现正确的结果
URL中的百分号编码,会对不属于ASCII码的字符和属于ASCII码但是又属于保留字的字符进行百分号编码,百分号编码就是对非ASCII码取Unicode内码再加%前缀
HTTP报文
常用请求方法
- GET:作为URL的一部分向服务器端发送,是浏览器默认请求方式
- 由于是URL的一部分,所以很容易从浏览历史记录中查到表单提交内容,不太安全
- 由于是URL的一部分,所以请求体就是URL中的query部分,没有显示的请求体
- URL长度有限制
- POST:用于提交表单数据或大批量的数据
- 有自己的请求体,相对比较安全
- 没有长度限制,所以可以提交大批量数据
- PUT:用于更新数据资源
- HTTP1.1版本不带有PUT方法的验证机制,所以存在一定的安全隐患,一般不使用
- DELEAT:用于删除数据资源
- HTTP1.1版本不带有DELEAT方法的验证机制,所以存在一定的安全隐患,一般不使用
- HEAD:与GET请求相同,不同的是只获取响应头,而没有响应体,所以多作用与超链接弹探测
- OPTIONS:用于查询接口支持的请求什么方法
- TRACE:回显服务器收到的请求,主要用于测试和诊断,容易引起一种XST(跨站追踪)的攻击方式,所以一般不使用
- CONNECT:开启客户端与请求资源之间的双向沟通通道,通常用于访问代理服务器
常用响应状态码
- 1XX:临时响应,已经接受需要继续处理,没有响应体
- 2XX:成功
200 OK
:请求已成功202 Accepted
:已接受,但未处理完成206 Partial Content
:服务器成功处理了部分内容,多用于请求部分内容,即断点续传完成
- 3XX:重定向
301 Moved Permanently
:永久移动,URI会变,浏览器会有缓存302 Found
:临时移动,URI不会变,浏览器不会有缓存304 Not Modified
:文件未修改,使用本地缓存文件
- 4XX:客户端请求错误
400 Bad Request
:客户端语法错误401 Unauthorized
:未授权的,请求要求客户身份认证403 Forbidden
:拒绝访问,没有权限404 Not Found
:资源未找到406 Non Acceptable
:无可接收的媒体类型416 Range Not Satisfiable
:请求部分资源内容范围错误
- 5XX:服务器错误
500 Internal Server Error
:服务器内部错误,无法完成请求502 Bad Gateway
:网关或代理服务器错误,无效的请求
报文头
通用报文头
可以通用于请求报文头和响应报文头
字段名 | 描述 |
---|---|
Cache-Control |
缓存控制 |
Connection |
逐跳首部,连接管理 |
Date |
创建报文的日期时间 |
Pragma |
报文指令 |
Trailer |
报文末端的首部 |
Transfer-Encoding |
指定报文主体的传输编码 |
Upgrade |
升级为其他协议 |
Via |
代理服务器的相关信息 |
Warning |
错误通知 |
Connection
:连接管理keep-alive
:网页打开请求结束后不会断开TCP连接,若再次发送请求还会使用该连接,HTTP1.1默认采用长连接close
:请求结束后就会断开TCP连接,若再次发送请求会重新建立连接,HTTP1.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
-
请求头只有:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-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
共存的情况下优先级高于Expires
s-maxage=x
:代理服务器请求源站点缓存后x秒内不再发起请求max-stale=x
:即使缓存已经过期了,但是在x秒内可以使用过期缓存public
:客户端和代理服务器都可以缓存private
:只能客户端可以缓存,只是声明性的
原理
使用Cache-Control
字段即可启动缓存机制,详细的缓存控制在上面通用报文头中
max-age=x
:请求缓存缓存后x秒内不再发起请求,与Expires
类似,是HTTP1.1的属性,与Expires
共存的情况下优先级高于Expires
Expires
:实体主体的过期的日期时间,与缓存控制中的max-age=x
类似,是HTTP1.0的字段,与max-age=x
共存的情况下,优先级低于max-age=x
If-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
对比文件是否修改
由步骤可知道,缓存的问题就是服务器更新,这些更新条件都是在文件过期的情况下对比文件是否跟新,为了解决这个问题,需要采用md5/hash值对静态资源文件进行唯一标识名,当服务器更新时,文件的名字就会更改,名字更改了就不会在使用缓存
浏览器操作对缓存的影响
用户操作 | 过期时间 | 文件对比 |
---|---|---|
地址栏回车 | 有效 | 有效 |
页面连接跳转 | 有效 | 有效 |
新打开窗口 | 有效 | 有效 |
前进后退 | 有效 | 有效 |
F5刷新 | 无效 | 有效 |
Ctrl+F5强制刷新 | 无效 | 无效 |
内容协商
原理
请求头 | 描述 | 响应头 |
---|---|---|
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
响应头信息 - 用户填写用户名和密码后,浏览器会自动将用户名和密码字符串使用冒号连接后,采用base64编码,放在请求头的
Authenticate
字段中(该字段值的前面还需要添加Basic空格前缀)发送给服务器 - 认证通过后返回200状态码,失败后继续返回401
Digest认证方式
- 客户端先发送请求,服务端返回401状态码要求用户身份认证,同时返回一个
WWW-Authenticate
响应头信息,该信息中会包含一个临时质询码(就是一个随机的字符串) - 用户填写用户名和密码后,浏览器会自动将用户名和密码字符串使用冒号连接后,使用临时质询码再base64编码,放在请求头的
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