认识HTTP
超文本传输协议(英语:Hyper Text Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法(所以又叫做超文本传输协议)。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。目前使用最广泛的版本是1.1的版本,HTTP是基于TCP协议的,在1.1版本中是默认开启 Keep-Alive(下文会说到对应字段)的,所以不用每次发起HTTP请求都建立链接然后请求完成之后释放链接(这样可以做到节省资源的效果)
HTTP请求准备
首先第一步就是现根据URL通过DNS解析找到对应的IP地址,然后上文也说道了HTTP是基于TCP协议的所以拿到IP之后就开始建立链接,当链接建立成功至此HTTP的请求准备就做完了就可以发送数据了
报文格式
请求报文格式
响应报文格式
ABNF
上文分别列举了请求报文和响应报文的格式图,只能多基本上大多数的请求都是按照上面两个图片进行封装的,但是上面两个图的格式不是最近准的,最严谨的HTTP报文格式描述形式是ABNF在RFC 5234中表明:ABNF用作internet中通信协议的定义语言,这里在补充一下 RFC: >RFC:请求意见稿(英语:Request for Comments,缩写:RFC),又翻译作意见征求,意见请求,请求评论是由互联网工程任务组(IETF)发布的一系列备忘录。文件收集了有关互联网相关信息,以及UNIX和互联网社群的软件文件,以编号排定。目前RFC文件是由互联网协会(ISOC)赞助发行。
比如:HTTP/1.1最早是在1997年的RFC 2068中记录的
- ABNF核心规则
- 报文格式
HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ]
可以再 rfc7230找到相关标准如下图:-
start-line:
如果是发送请求则start-line是请求行也就是 request-line如果是响应报文则是 status-line
-
request-line:
翻译一下就是请求方式也就是 get、 post等,SP就是一个空格,然后是请求的对象,就是对应的URL又是一个空格然后 http版本最后加一个回车换行
例如:POST /address HTTP/1.1 -
status-line:
翻译过来就是:http版本+空格+状态码+返回reason+回车换行
-
header-field:
就是头信息中的键值对,*()表示有0个或者多个,然后每个后面都有个回车换行
-
message-body:
请求体也就是返回信息的地方或者传递信息的地方不难发现ABNF翻译过来之后基本上和上图的格式差不太多
-
头部字段
- User-Agent
浏览器的身份标识字符串,就比如我很很多时候访问一个下载软件的网页同是一个下载按钮我们在Windows上下载下来的是.exe格式的文件在Mac上面下载下来的就是.dmg格式的文件,这个就是后端通过判断该字段识别到了系统信息然后选择对应的字符串下载
- Host
服务器域名、端口号 - Date
发送该消息的日期和时间 - Referer
表示浏览器所访问的前一个页面,多用在防盗链上面,比如你们自己服务器上面上传了很多自己的图片,然后又不希望这个图片被人拿到到处地方去使用,这个就可以加一个Referer,不是冲指定页面跳转过来的服务器就不返回图片资源就好 - Content-Type:
请求体类型,例如: - **Content-Length ** 请求体长度
- Accept.
能够接受的响应内容类型 - Accept-Charset.
能够接受的字符集 - Accept-Encoding
能够接受的编码方式列表 - Accept-Language
能够接受的响应内容的自然语言列表
例如:zh-CN,zh;q=0.9
这里需要注意的是这个 q值q值越大,表示优先级越高,如果后面没有跟 q则说明q=1,如上 zh-CN的q值是1, zh的q值是0.9(注意分割符师逗号不是分号) Accept-Charset、 Accept-Encoding都可能出现 q值其含义都是一样的 - Range.
仅请求某个实体的一部分,字节便宜以0开始 - Connection.
想要优先使用的链接类型,keep-alive,不会发送接收完毕马上断开连接,会在指定时间内没有请求才会断开连接 - server
服务器的名字 - Last-Modified.
锁清秋的对象的最后修改日期 - Expires
指定一个时间,超过改时间则认为该响应已经过期 - Content-Disposition.
一个可以让客户端下载文件并建议文件名的头部 - Accept-Ranges
服务器支持哪些种类的部分内容范围 - Content-Range
这条部分消息是属于完整消息的哪部分 - Location
用来进行重定向,或者在创建了某个新资源时使用,以前前后端没有分离之前比如写个登录页面登录的页面路由是/login
登录完成需要跳转到首页路由是/home
,这个时候就可以用重定向,登录成功重定向到首页此时登录完成就可以直接跳转到首页 - Origin
发起一个针对跨域资源共享的请求Origin就是发起跨域请求的源地址,例如一个域名是tudou.com现在想访问一个tudou2.com域名下的东西此时就需要跨域访问,此时的Origin就等于tudou.com - Access-Control-Allow-Origin
指定哪些网站可参与到跨来源资源共享,上文中如果客户端请求头中含有Origin但是服务器没有指定Access-Control-Allow-Origin(没有指定的情况下默认就是同域名访问)的情况下虽然最终请求的数据会下发到浏览器,但是浏览器发现并不支持跨域共享资源,或者当前域名不在跨域共享资源的设置范围内,则不会返回数据Access-Control-Allow-Origin主要是后端同学设置的如下:
response.setHeader("Access-Control-Allow-Origin","http://www.tudou.com");
这样上文中的tudou.com就能访问tudou2.com域名下的东西。 - Cookie
是浏览器保存在客户端硬盘上的,如果服务器返回Set-Cookie,浏览器就会将对应的Cookie存到本地,对应的有一个session,session是存储在服务器内容中的两者配合实现会话跟踪技术,例如登录成功后服务器就会将用户名和密码存到session对应的就会生成一个sessionId,然后将这个id返回给客户端,这个时候客户端每次像服务器发送请求在头信息中将sessionId赋值给cookie,这就有了登录的凭证实现了会话跟踪的技术。 (这里需要注意的是cookie在浏览器关闭的时候也就失效了而session默认的是半个小时失效当然服务器可以设置失效时间同时也可以直接让session失效) - Set-Cookie
返回一个cookie让客户端保存 - Cache-Control
状态码
在RFC 2616 10.Status Code Definitions规范中定义,状态码指示HTTP请求是否已成功完成,状态码主要分为5类(注意一下是状态码范围并不是有那么多的状态码比如188就没有这个状态码):
- 信息响应:100-199
常用的状态码是100 Continue
请求的初始部分已经被服务器收到,并且没有被服务器拒绝。客户端应该继续发送剩余的请求,如果请求已经完成,就忽略这个响应。 其实就是在请求一个资源之前先发送一个请求里面还有URL和请求体,服务器通过判断URL或者是请求体,来判断这个资源是否能给客户端,如果不能给的话直接返回错误码,如果可以则返回100,让客户继续发送请求体。主要用在客户端能判断到自己索要的资源极有可能被服务器拒绝的情况下使用会节省性能。 - 成功响应:200~299
常见状态码:200 请求成功 - 重定向:300~399
常见状态码:- 302 Found:
请求的资源被暂时的移动到了由Location头部指定的URL上,具体的例子可以看上文说到请求头字段时候的举例 - 304 Not Modified:
说明无需再次传输请求的内容,也就是说可以使用缓存的内容。
就比如一些静态文件:图片、js\css文件啊,第一次拉取此时会缓存到本地,如果再次拉取的时候服务器会判断如果服务器觉得你缓存中的东西没有变过还是最新的就不会再将对应的资源返回给客户端,而是返回 304的状态码这个时候客户端就会知道此时资源需要冲缓存中查找,当然还可以是客户端在请求头中写入If-Modified-Since 和 If-None-Match,服务器通过这个两个字段来判断缓存是否过期
- 302 Found:
- 客户端错误:400~499
常见状态码:(返回4该范围的状态码一般都是客户端的问题了,当然后端也可以将后端的问题返回状态码是400多但是这种情况还是很少见的)- 400 Bad Request:由于语法无效,服务器无法理解该请求。例如上文说到的请求头格式如果没有按照上文的格式来,服务器就没办法解析你的请求头所以就会报错400,还有中可能就是服务器需要的参数发现在请求体中或者url中没有,这个时候后端同学就可以主动返回一个400给客户端。
- 401 Unauthorized:由于缺乏目标资源要求的身份验证凭证。例如一些资源是需要用户登录成功根据用户的身份来返回的就是超管才会给你否则不给这个时候就会需要一个身份凭证,一般都是登录成功之后后端会返回一个token,如果在请求一些需要身份凭证的接口的时候就需要带上这个token,否则返回401
- 404 Not Found:服务器端无法找到所请求的资源,例如服务器上有/hello还有/login,结果你非要访问/home这个时候就会提示404
- 405 Method Not Allowed:服务器禁止了使用当前HTTP方法的请求
- 406 Not Acceptable:服务器端无法提供与Accept-Charset以及Accept-Language指定的值相匹配的响应
- 408 Request Timeout:服务器想要将没有在使用的连接关闭,有些服务器会在空闲的时候发送这种消息,表示想要关掉TCP链接
- 服务器错误 :500~599
常见错误码:- 500 Internal Server Error:所请求的服务器遇到意外的情况并阻止其执行请求,其实就是服务器崩溃了
- 501 Not Implemented:请求的方法不被服务器支持,因此无法被处理
- 502 Bad Gateway:作为网关或代理角色的服务器,从上游服务器(如tomcat)中接收到的响应是无效的
- 503 Service Unavailable:服务器尚未处于可以接受请求的状态,通常造成这种情况的原因是由于服务器停机维护或者已超载
form提交
就比如下图(这里拿QQ的注册中心做示例): 在看一下这里的源代码
这里就是一个表单提交。
表单提交支持get和post这个需要设置表单提交的method属性来确认是get请求还是post请求,其中比较重要的一个属性是 enctype,需要注意的是这个属性只有在 method是 post的时候才会生效,enctype的取值有以下两种:
-
application/x-www-form-urlencoded
enctype的默认值就是这个,该值的作用主要是定义请求体重传递参数的一个格式以及字符的编码方式:用&分隔参数,用=分隔键和值,字符用URL编码方式进行编码如下图所示: -
multipart/form-data
需要注意的是文本上传必须选择这种类型,其他类型服务器接收到的可能只是文件的名称以及文件的格式接收不到客户端传递的文件二进制数据作用和上文中的一样的无非就是这里定义的请求体的格式和上文中的application/x-www-form-urlencoded 不同,如下图所示:
,首先就是 content-type中除了声明了编码类型是multipart/form-data之外还声明了 boundary,然后下文中的请求体也被分成了一段一段的,然后细心的同学可能会发现每一段的分割就是用的 boundary来分割,无非就是在 boundary前面又多加了两个 -,然后最后一行又加了一个 boundary最后一行的 boundary前后都添加两个 -,这种格式的规定在 RFC 1521中都是有记录的可以查一下RFC 1521验证一下上文中的说法
从这里就可以发现Content-type的不同对应传递给服务器的请求体编码格式可能就不同就如上文中的两种,所以在客户端发送给服务器数据的同时也必须告诉服务器客户端这里的编码这是是什么样的,服务器根据他支持的对应的编码格式来解析请求体中的数据。需要注意的点是我们经常在开发的过程中调试接口的时候就会收到一些接口的报错提示不支持某种格式的数据,就是应为服务器这边只支持application/x-www-form-urlencoded格式的解析没有做multipart/form-data 格式的解析,所以后端就没办法拿到准确的请求体数据这个时候就会报错,所以客户端在传参的时候可以和后端的同学确认一下他们支持的格式是哪个,然后前端就传递那种格式的数据。
认识HTTPS
HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。它被广泛用于万维网上安全敏感的通讯,例如交易支付等方面
其实就是在HTTP的基础上将消息报文进行了加密传输,具体如何加密可参考常见的加密方式。
HTTPS的默认端口号是443(HTTP是80)
SSL/TLS
TLS的前身是SSL,被叫做传输层安全性协议。
他的作用其实就是将报文进行加密然后在给传输层进行传输。
所以我们大概也可以才到它主要作用在应用层和传输层之间如下图所示:
HTTPS的通信过程
- 建立TCP链接
- 建立TLS链接
- HTTP请求和响应
其实就多了第二步,剩下和HTTP一样,多第二步的原因也是应为需要只要加密密钥证书等信息
TLS 1.2的链接
大致流程如下:
- 第一步:Client Hello
- TLS版本号
- 支持的加密组件(Cipher Suite)列表
加密组件(Cipher Suite):指的是加密算法和密钥长度等 - 一个随机数
- 第二步:Server Hello
- TLS版本号
- 选择的加密组件
从客户端提供的加密组件列表中选择一个 - 一个随机数
-
第三步:Certificate
将证书给到客户端 -
第四步:Server Key Exchange
用以实现ECDHE算法的其中一个参数(Server Params)ECDHE是一种密钥交换算法(为了防止伪造,Server Params经过了服务器私钥签名)
-
第五步:Server Hello Done
告诉客户端协商部分结束,到目前为止客户端和服务器通过明文共享了Client Random、Server Random、Server Params,而且客户端已经拿到了服务器的公钥证书,然后客户端就会检验证书的真实有效性 -
第六步:Client Key Exchange
证书验证成功后就会给服务器再发送一个用以实现ECDHE算法的另一个参数此时客户端和服务器就都有了Server Params、Client Params,
然后客户端和服务器都可以使用ECDHE算法根据Server Params、Client Params计算出一个新的随机密钥串:Pre-master secret
然后结合Client Random、Server Random、Pre-master secret生成一个主密钥
最后利用主密钥衍生出其他密钥:客户端发送用的会话密钥、服务器发送用的会话密钥等 -
第七步:Change Cipher Spec
告知服务器:之后的通信会采用计算出来的会话密钥进行加密
- 第八步:Finished
包含连接至今全部报文的整体校验值(摘要),加密之后发送给服务器
然后服务器进行解密如果解密成功则这次握手是成功的 - 第九步:Change Cipher Spec 同样的服务器告知客户端会话密钥
- 第十步:Finished
最后也是将全部报文的摘要用会话密钥加密后发送给客户端 如果客户端解密成功标识链接成功,接下来就是发送正文了