今天我们来简单说一下http协议,一个对大部分人而言“最熟悉的陌生人”。说熟悉,是因为http协议深入到生活的每一个角落,大多数人对它至少是有所耳闻,看看你正在浏览的网页地址栏上前四个字母,没错就是它,http。说陌生,是因为它的内涵是如此丰富,即使计算机相关专业的同学,对它的了解也只是皮毛而已。因此,我们这里对http的介绍也是浅尝辄止,仅仅足以应付java web开发的日常,想有更深入了解,甚至把它作为职业的同学,请去参考权威的书籍或规范,如《HTTP权威指南》。
OSI七层网络协议
从某种意义上讲,互联网的本质就是一系列的网络协议。那么什么是协议呢?协议就是一群人商量之后达成共识的一套标准。在互联网中存在着成百上千的网络协议,它们有不同的分工,执行着不同的任务。这么多杂乱无章的协议怎么管理呢?有一天,有人提出来,我们把协议分分层吧。大家一听,这主意不错,于是决定人为地把这些协议归到不同层。那么究竟分几层呢?有人说,简单点,4层吧;有人说,4层不够,5层比较合理;还有人说,5层也有区分不出来的情况,7层吧。OSI(Open System Interconnection)就是说7层的人搞出来的模型,叫开放性通信系统互连参考模型,它提出的7层从上到下依次是应用层、表示层、会话层、传输层、网络层、数据链路层和物理层,其中上面4层用于定义web应用程序的功能,下面3层用于端到端的数据流。这些层都是人为划分的,并非物理存在的层。
http属于应用层的协议,是负责应用程序的通信服务的,是我们做应用开发的工程师们主要需要关注的层次。顺便一提,其他我们熟悉的tcp协议属于第4层,ip协议属于第3层,http协议正是架设在tcp/ip协议之上的协议。
https
有同学说,我现在在看的地址栏不是http,是https啊。https实际上是安全版的http,它是在http协议下加上SSL协议,SSL正是https安全的基础。https和http主要有以下几点不同:
一是https协议需要申请SSL证书,这些证书通常是收费的。
二是http协议中,信息是明文传输的,而https协议中信息是加密传输的。
三是http和https使用不同的连接方式,http默认的端口是80,而https是443。
四是http是无状态的协议,这点在后面文章中还会反复提及。而https是带有身份认证的协议,因此不能认为是无状态的。
URI和URL
http协议使用URI(Uniform Resource Identifiers)来传输数据和建立连接,URI全称为统一资源标识符,是一个指向资源的字符串,如在书本界,ISBN就是书本的URI,它可以唯一地标识一本图书。
URL(Uniform Resource Locator)指的是统一资源定位符,把“标识”换成“定位”,一词之差,意味着URL的功能更加具体,是用于定位资源的字符串。由于定位资源一定能够标识资源,因此,URL是URI的子集,也就是说,所有URL都是URI。在http协议中,我们使用的URI通常为URL。
一个典型的URL形式如下
Schema://host:port/path?query#hash
其中Schema是指协议,即我们一直说的http和https等;host指主机名,可以是域名或者IP地址;port指端口号,范围从0到65535;path是资源的具体路径,可以为多个层次;query指的是查询条件,可以用于传递GET类请求的参数;hash为片段标识符,用于定位资源中的锚点,在目前流行的单页面应用中,通常用片段标识符来定位单页面应用中的子页面。
请求
http协议用于在客户端(浏览器)和服务器之间建立连接,由浏览器向服务器发起请求,服务器接收到请求后,向浏览器返回响应。因此,http协议的核心在于请求和响应。
一个典型的http请求由请求行、请求头部、空行和请求数据四个部分组成,其中尤其注意的是空行不可省略。请求行包括请求方法、URL以及http协议版本号,中间使用空格隔开,一个典型的请求行形式如下:
GET /abc.jpg HTTP/1.1
请求方法常见的有GET、POST、PUT、DELETE、HEAD和OPTIONS,其中GET和POST是最常用的请求方式,而目前流行的RESTful风格的应用会用到上述六种请求。按照RESTful风格的规范用法,GET请求用于从服务器获取数据,POST用于更新数据,PUT用于提交数据,DELETE用于删除数据,这四种请求方式可以与数据库的CRUD完美地对应。HEAD和OPTIONS是两个应用相对较少的请求,其中HEAD请求用于请求获取由Request-URI所标识的资源的响应消息报头,说白了就是一个仅含有头信息的GET请求;OPTIONS请求用于获取当前URL支持的请求方式,如“GET, POST”表示当前URL支持GET和POST请求。
请求头部用于向服务器提供客户端的相关信息,以键值对的形式存在,格式为“属性名:属性值”。一个典型的请求头如下:
Host img.mukewang.com
User-Agent Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36Chrome/51.0.2704.106 Safari/537.36
Accept image/webp,image/*,*/*;q=0.8
Referer http://www.imooc.com/
Accept-Encoding gzip, deflate, sdch
Accept-Language zh-CN,zh;q=0.8
这里各项请求头的含义不再展开。
请求数据是客户端向服务器提供的数据,可以为空。GET请求使用URL的方式传参,因此请求数据通常为空。POST请求使用请求数据向服务器传参数,如提交的表单数据。请求数据的格式如下:
name=gseinfeld&age=30
响应
典型的http响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。其中状态行由响应协议版本号、 状态码、 状态消息组成,同样由空格分隔。协议版本号与请求中的协议版本号相同,状态码表明服务器当前的状态,状态消息对状态码进行进一步的解释。一个典型的响应状态行如下:
HTTP/1.1 200 OK
状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
常见状态码和状态信息包括:
状态码 | 状态信息 | 含义 |
---|---|---|
200 | OK | 客户端请求成功 |
302 | Redirect | 暂时重定向 |
400 | Bad Request | 客户端请求有语法错误,不能被服务器所理解 |
401 | Unauthorized | 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用 |
403 | Forbidden | 服务器收到请求,但是拒绝提供服务 |
404 | Not Found | 请求资源不存在,如输入了错误的URL |
500 | Internal Server Error | 服务器发生不可预期的错误,这是在java web开发中最常见的错误码了 |
503 | Server Unavailable | 服务器当前不能处理客户端的请求,一段时间后可能恢复正常 |
响应的消息报头用于向客户端告知一些服务器信息或者数据相关信息,典型的响应消息报头如下:
Server: nginx
Date: Sat, 23 Jul 2016 07:28:11 GMT
Content-Type: application/octet-stream
Content-Length: 1430256
Last-Modified: Fri, 22 Jan 2016 14:49:14 GMT
Connection: close
Expires: Sat, 23 Jul 2016 15:28:11 GMT
Cache-Control: max-age=28800
Accept-Ranges: bytes
响应正文即响应的数据,如json数据:
{"name":"g_seinfeld", "age": 30}
http/2.0
http/2.0是“下一代”的http协议,这意味着目前大多数网站仍然在使用http/1.1协议。但是http/1.1协议有一些饱受诟病的地方,在http/2.0中得到了较好地解决,也就是说未来http/2.0取代http/1.1协议是一个必然,只不过这个过程会比较缓慢。javaEE 8.0起开始全面支持http/2.0协议,以后做java web开发的时候,大家可以尝试使用http/2.0协议,做第一批吃螃蟹的人。
那么http/2.0协议有哪些优点呢?我们这里简要来说几点:
- 不同于基于文本的http/1.1协议,http/2.0协议是基于二进制的,它可以方便地对帧(数据交换的基本单元,必须归属于流中)进行分层。
- http/2.0协议具有多路复用的特点。每个http/2.0的连接都可以包含多个并发的流,这些流可以被客户端或者服务端单独的建立、关闭,或者在两端之间共享。
- 服务器推送。在客户端和服务端建立过连接之后,服务端可以将客户端可能需要的资源主动的推送给客户端,而不必等待客户端主动请求。
总结
对http的介绍就这么多,了解这些内容基本可以满足java web开发的需求。这一节的内容和java直接关系不大,也比较枯燥,但是理解它可以从原理上掌握java web开发的各种设计和开发思路。