在上一篇文章Android网络编程简介中我们说过,大部分的Android应用网络通信都是基于Http协议(超文本传输协议)的,Http协议属于应用层的协议,而应用层协议的作用是用来规定传输数据的格式,以便通信双方能够按照规则来解读数据。Http是基于TCP/IP通信协议来传递数据的,其通信依赖于传输层的TCP协议。Http协议由请求和响应组成,属于标准的客户端服务器模型。
上面说过,HTTP协议是属于应用层的协议,在网络分层中,应用层属于最上面的一层,其作用是规定传输数据的格式,以便通信双方都能按照规定的格式解读数据,真正的数据传输依赖于传输层,HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候就成了我们通常说的HTTPS协议。如下图所示:
以我们平时最常见的请求Web页面举例,我们来分析Http协议的工作流程。HTTP协议定义了客户端发送请求数据的格式以及服务端返回的数据格式,通信双方只需要按照规定的格式来解析数据即可解读数据。HTTP采用请求/响应模式,客户端向服务端发送一个请求报文,请求报文的内容包括请求的方法、URL、协议版本、请求头部和请求数据;服务端以一个状态行作为响应,响应内容包括协议的版本、请求状态响应码、服务器信息、响应头部和响应内容。这中间的数据传输依赖于TCP协议。详细步骤如下:
1、客户端连接到服务器
客户端发起一个TCP连接请求,经过三次握手和服务器建立TCP连接;
2、发送请求数据
按照HTTP协议规定的格式组装请求报文,并通过TCP连接向服务端发送请求报文;
3、服务端接收请求报文并处理
服务端通过TCP连接收到客户端发送过来的请求报文后,按照规定格式解析数据,根据解读的数据生成对应的响应报文,生成的响应报文也要遵循HTTP协议;
4、服务端发送响应报文给客户端
服务端将生成的响应报文通过TCP连接发送给客户端
5、关闭TCP连接
服务端将数据发送给客户端后,如果connection模式为close,则服务端主动关闭TCP连接,客户端被动关闭连接,通信结束;如果connection模式为keepalive,则该连接会保持一段时间,则该时间段内可以继续通过连接传输数据;
6、客户端处理响应数据
客户端收到响应报文后,按照HTTP协议规定格式解析响应报文并处理。
从上面的流程可以看出,HTTP协议的主要作用是规定通信双方传输数据的格式,而真正的传输过程是有传输层的TCP连接来完成的。
由上面我们知道,HTTP协议主要的作用就是规定传输双方的数据格式。HTTP协议是基于请求/响应模式的,其报文有从客户端到服务端的请求和从服务端到客户端的响应组成。
HTTP协议的请求报文由请求行、请求头部、空行、请求数据四个部分组成。
下面我们用postman模拟发送一个post请求,并用charles抓包查看数据格式
用charles查看请求报文数据:
POST /lotto/android/v1.0/order-group/queryOrderGroupPersonInfo HTTP/1.1
cache-control: no-cache
Postman-Token: 800ec750-6ee8-4b2b-a879-f5d854115862
Content-Type: application/json
User-Agent: PostmanRuntime/3.0.11-hotfix.2
Accept: */*
Host: sitapp.2ncai.com
accept-encoding: gzip, deflate
content-length: 38
Connection: close
{"seeType":1,"source":1,"userId":"30"}
HTTP请求报文格式如图:
请求行由请求方法、URL字段和HTTP协议版本组成,格式如下:
Method Request-URI Http-Version CRLF
CRLF表示回车和换行
在上面的例子中,请求行如下:
POST /lotto/android/v1.0/order-group/queryOrderGroupPersonInfo HTTP/1.1
HTTP请求的方法分为8种,分别是GET、POST、HEAD、PUT、DELETE、TRANCE、CONNECTON、OPTIONS。对于我们平时的开发来说,用到最多的就是GET和POST了
GET:请求获得Request-URL所标识的资源
POST:在Request-URL所标识的资源后附加新的数据,即可以向服务端发送请求数据
HEAD:请求获取Request-URL所标识的资源的响应消息报头
PUT:请求服务器存储一个资源,并用Request-URL作为其标识
DELETE:请求服务器删除Request-URL所标识的资源
TRACE:请求服务器回送收到的请求信息,主要用于测试或者诊断
CONNETC:HTTP1.1中预留的能够将连接改为管道方式的代理服务器
OPTIONS:请求查询服务器性能,或者查询与资源相关的选项或需求
在请求行之后会有0个或者多个请求报头,每个请求报头都包含一个名字和一个值,他们之间用英文冒号(:)分隔,例如上面的例子中请求报头如下:
cache-control: no-cache
Postman-Token: 800ec750-6ee8-4b2b-a879-f5d854115862
Content-Type: application/json
User-Agent: PostmanRuntime/3.0.11-hotfix.2
Accept: */*
Host: sitapp.2ncai.com
accept-encoding: gzip, deflate
content-length: 38
Connection: close
关于请求报头我们后面说到消息报头的时候在统一说明。
在HTTP协议中,规定空行是必须需要的,即使后面的请求数据为空,也必须有空行
请求数据不在GET方法中使用,而是在POST中使用,它表示向服务器附加的请求数据。POST方法使用于需要向服务器提交数据的请求,比如客户填写表单需要提交到服务器就可以使用POST方法发起请求。
在上面例子中,请求数据如下:
{"seeType":1,"source":1,"userId":"30"}
HTTP的响应报文是指服务端返回给客户端的报文,响应报文的格式如下:
由上面可知,响应报文也分为四个部分:状态行、响应报文、空行、响应正文。
比如上面的例子中,响应报文如下:
HTTP/1.1 200
Date: Sat, 11 Aug 2018 04:24:25 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Application-Context: application:test:8160
Server: my_server
{"success":1,"errorCode":"10001","message":"正确","data":{"userName":"CCCC","userId":30,"headPic":"https://sitres.2ncai.com/_upload_images/user/head/1711181009252.png","winCount":32,"winAmount":2580477.84,"orderCount":249,"orderSucRate":0.36,"customizationCount":0,"winBwCount":0,"winSwCount":7,"winWCount":10,"winQCount":20,"winOtherCount":42,"orderGroupLotteryBOs":[{"lotteryCode":100,"lotteryName":"双色球","lotteryType":1,"grade":0,"orderCount":239,"orderSucRate":0.03,"winCount":3,"winAmount":324800.0},{"lotteryCode":101,"lotteryName":"七乐彩","lotteryType":1,"grade":0,"orderCount":247,"orderSucRate":1.0,"winCount":0,"winAmount":0.0},{"lotteryCode":102,"lotteryName":"大乐透","lotteryType":1,"grade":0,"orderCount":243,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":103,"lotteryName":"排列5","lotteryType":1,"grade":0,"orderCount":246,"orderSucRate":1.0,"winCount":0,"winAmount":0.0},{"lotteryCode":104,"lotteryName":"排列3","lotteryType":1,"grade":0,"orderCount":245,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":105,"lotteryName":"福彩3D","lotteryType":1,"grade":0,"orderCount":244,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":107,"lotteryName":"七星彩","lotteryType":1,"grade":0,"orderCount":249,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":300,"lotteryName":"竞彩足球","lotteryType":2,"grade":0,"orderCount":235,"orderSucRate":0.34,"winCount":30,"winAmount":1381706.71},{"lotteryCode":301,"lotteryName":"竞彩篮球","lotteryType":2,"grade":0,"orderCount":6,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":304,"lotteryName":"十四场","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.5,"winCount":2,"winAmount":864000.0},{"lotteryCode":305,"lotteryName":"九场胜负彩","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":306,"lotteryName":"北京单场","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.5,"winCount":2,"winAmount":9971.13}]},"serviceTime":1533961465544}
状态行的格式:HTTP-Version Status-Code Reason-Phrase CRLF
其中HTTP-Version表示服务器HTTP协议的版本,Status-Code表示响应的状态码,Reason-Phrase表示状态码的文本描述。状态码由三位数字组成,其中首位数字定义了响应的类别,且有5种类别:
100-199:指示信息,收到请求后,需要请求者继续执行操作
200-299:请求成功,请求已被成功接收并处理
300-399:重定向,要完成请求需要进行更进一步操作
400-499:客户端错误,请求有语法错误或者请求无法实现
500-599:服务端错误,服务器执行错误,无法正确处理请求
常见的状态码如下:
200 OK:客户端请求成功
400 Bad Request:客户端请求有语法错误,服务端无法理解
403 Forbidden:服务端收到请求,但是拒绝提供服务
404 NOT FOUND:服务器无法正常提供信息,或是服务器无法回应
500 Internal Server Error:服务器内部错误,无法完成请求
503 Server Unavailable:服务器当前无法处理客户端请求,一段时间后可能恢复正常
用于传递服务器自身的信息,和请求报头对应,这个例子中的响应报头如下:
Date: Sat, 11 Aug 2018 04:24:25 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Application-Context: application:test:8160
Server: my_server
关于响应报头,我们后面统一解释
在HTTP协议中,规定空行是必须需要的,即使后面的响应正文为空,也必须有空行。
服务端返回给客户端的正文数据,在这个例子中,响应正文如下:
{"success":1,"errorCode":"10001","message":"正确","data":{"userName":"CCCC","userId":30,"headPic":"https://sitres.2ncai.com/_upload_images/user/head/1711181009252.png","winCount":32,"winAmount":2580477.84,"orderCount":249,"orderSucRate":0.36,"customizationCount":0,"winBwCount":0,"winSwCount":7,"winWCount":10,"winQCount":20,"winOtherCount":42,"orderGroupLotteryBOs":[{"lotteryCode":100,"lotteryName":"双色球","lotteryType":1,"grade":0,"orderCount":239,"orderSucRate":0.03,"winCount":3,"winAmount":324800.0},{"lotteryCode":101,"lotteryName":"七乐彩","lotteryType":1,"grade":0,"orderCount":247,"orderSucRate":1.0,"winCount":0,"winAmount":0.0},{"lotteryCode":102,"lotteryName":"大乐透","lotteryType":1,"grade":0,"orderCount":243,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":103,"lotteryName":"排列5","lotteryType":1,"grade":0,"orderCount":246,"orderSucRate":1.0,"winCount":0,"winAmount":0.0},{"lotteryCode":104,"lotteryName":"排列3","lotteryType":1,"grade":0,"orderCount":245,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":105,"lotteryName":"福彩3D","lotteryType":1,"grade":0,"orderCount":244,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":107,"lotteryName":"七星彩","lotteryType":1,"grade":0,"orderCount":249,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":300,"lotteryName":"竞彩足球","lotteryType":2,"grade":0,"orderCount":235,"orderSucRate":0.34,"winCount":30,"winAmount":1381706.71},{"lotteryCode":301,"lotteryName":"竞彩篮球","lotteryType":2,"grade":0,"orderCount":6,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":304,"lotteryName":"十四场","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.5,"winCount":2,"winAmount":864000.0},{"lotteryCode":305,"lotteryName":"九场胜负彩","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.0,"winCount":0,"winAmount":0.0},{"lotteryCode":306,"lotteryName":"北京单场","lotteryType":2,"grade":0,"orderCount":2,"orderSucRate":0.5,"winCount":2,"winAmount":9971.13}]},"serviceTime":1533961465544}
消息报头分为通用报头、请求报头、响应报头和实体报头等。消息报头由键值对组成,每行一对,关键字用“:”隔开。
通用报头既可以出现在请求报头中,也可以出现在响应报头中,常见的通用报头如下:
Date:表示消息产生的日期和时间
Connection:允许发送指定连接的选项。例如可以指定连接是“Keep-Alive”,表示在请求完成后继续保持连接
Cache-Control:用于指定缓存指令
请求报头用来通知服务端关于客户端的请求信息,常见的请求报头如下:
Host:请求的主机名
User-Agent:发送请求的浏览器类型、操作系统等信息
Accept:客户端可识别的内容类型列表,用于指定客户端接受哪些类型的信息
Accept-Encoding:客户端可识别的数据编码
Accept-Language:表示客户端所支持的语言类型
Transfer-Encoding:告知接收端为了保证报文的可靠传输,对报文采用了什么类型的编码方式
响应报头用来告知客户端关于服务端的响应信息,常见的响应报头如下:
Location:用于重定向客户端到一个新的位置,常用在更换域名的时候
Server:包含服务端用来处理请求的系统信息,与请求报头中的User-Agent向对应
实体报头用来定义被传送资源的信息,其即可用在请求也可用在响应中。常见的实体报头如下:
Content-Type:发送给接收者的实体正文的媒体类型
Content-Length:实体报文的长度
Content-Language:描述资源所用的自然语言
Content-Encoding:实体头用于压缩媒体类型。如果存在,它的值表示哪些编码应用于实体主体。它让接收端知道,如何解码以获取Content-Type标题引用的媒体类型
Last-Modified:用于指示资源的最后修改时间
Expires:用于指示资源的过期时间
HTTP协议的主要特点如下:
1、支持C/S(客户端/服务器)模式
2、简单快速:HTTP协议规则简单,客户端向服务器请求服务时,只需要传递请求方法和路径。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快
3、灵活:HTTP协议虽然简单,但是其功能强大,允许传递任意类型的数据对象
4、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间。(当今多数服务器支持Keep-Alive功能,使用服务器支持长连接,解决无连接的问题)
5、无状态:无状态是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即客户端发送HTTP请求后,服务器根据请求,会给我们发送数据,发送完后,不会记录信息。(使用cookie机制可以保持session,解决无状态的问题)
由于HTTP协议规则简单,功能强大,使得其被广泛使用,HTTP协议的安全性问题也越来越受到重视,由于HTTP协议只规定了传输数据的格式,其是以明文方式发送内容,不提供任何方式的数据加密,如果攻击者拦截了客户端和服务端的报文数据,就可以直接读懂其中的信息,因此,HTTP协议并不适用于敏感数据的传输。为了解决HTTP的这一缺陷,引入了HTTPS协议,HTTPS叫做安全套接字超文本传输协议,HTTPS协议是在HTTP协议的基础上加上了SSL协议,SSL依靠证书来验证服务器的身份,并为客户端和服务器之间的通信加密。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTP协议的工作流程
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web服务器利用自己的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通信。
HTTPS协议的优点
尽管HTTPS并非绝对安全,掌握根证书的机构、掌握加密算法的组织同样可以进行中间人形式的攻击,但HTTPS仍是现行架构下最安全的解决方案,主要有以下几个好处:
(1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
(2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
(3)HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
(4)谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。
HTTPS协议的缺点
(1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长近50%,增加10%到20%的耗电;
(2)HTTPS连接缓存不如HTTP高效,会增加数据开销和功耗,甚至已有的安全措施也会因此而受到影响;
(3)SSL证书需要钱,功能越强大的证书费用越高,个人网站、小网站没有必要一般不会用。
(4)SSL证书通常需要绑定IP,不能在同一IP上绑定多个域名,IPv4资源不可能支撑这个消耗。
(5)HTTPS协议的加密范围也比较有限,在黑客攻击、拒绝服务攻击、服务器劫持等方面几乎起不到什么作用。最关键的,SSL证书的信用链体系并不安全,特别是在某些国家可以控制CA根证书的情况下,中间人攻击一样可行。
1、HTTP协议属于应用层的协议,其网络分层的层面来说,其主要功能是规定传输数据的格式,而真正的数据传输则交给传输层的TCP协议;
2、HTTP协议具有简单快速、灵活、无连接、无状态等特点;
3、HTTP协议传输数据是以明文的方式传输,并不提供任何方式的数据加密,为了确保敏感数据的安全性,在HTTP协议下加入了SSL协议,即构成了HTTPS协议,HTTPS协议通过证书来验证服务器的身份,并对通信数据进行加密处理;
4、HTTPS协议虽然增强了数据的安全性,但是也付出了一定的代价,比如会使页面的加载时间变长,增加耗电等;