网络协议系列____HTTP(2)


引言

这篇文章继续对HTTP协议进行说明。


正文

一个http事务包括客户向HTTP服务器发送请求以及服务器向客户端发送响应两个过程。根据事务的特点,这两个过程具有原子性,任何一个过程失败都会进行回滚(恢复事务之前的状态)。从请求与响应的角度出发,http的知识点都是围绕这两个角度展开的。每次客户的请求都会向服务器发送一个请求报文,请求报文的结构包括请求行、首部行、空行和请求体,一个http响应包括响应行、首部行、空行和响应体。http是基于TCP协议之上的应用层协议,默认使用80端口进行传输,也有基于SSL/TSL协议的https协议,默认使用443端口进行传输。

http协议虽然是基于TCP传输协议的,但确实无状态的,就是说每次完成一个事务后,客户端与服务器之间的连接就会断开,服务器不保存任何客户端的信息。但是人们发现无状态会降低使用体验,最直观的例子就是当我们登陆一个网站不小心退出想再次登陆的时候,因为http是一种无状态协议,所以用户的登陆信息需要重新输入,显然很影响使用体验,于是人们就想出了后来我们耳熟能详的Cookie和Session(后面还会提到)。

http协议到目前有两个版本,http1.0和http1.1,现在目前普遍再使用的是http1.1的版本。http1.1在http1.0的基础增加以下特性:

  • http1.1默认支持长连接
  • http1.1在消息头中增加Host域
  • http1.1增加了100、101、203等响应状态码
  • http1.1增加OPTIONS,PUT,DELETE,TRACE,CONNECT这些Request方法
  • http1.1使用了更完整的缓存机制(后面还会提到)

下面就从请求与响应两个角度说明http协议的方方面面

http请求

前面提到http协议(这里介绍的都是基于http1.1版本)请求会发送给一个请求报文,我们从这个请求报文入手,详细说明http请求是什么鬼,下面是一个http请求的模板

其中sp表示空格,cr表示回车,lf表示换行,注意到从请求行到主体,每一行都包括回车和换行,中间的空行是为了区分请求头和请求主体的。空行之前的都是请求头,空行之后的是具体的请求消息主体。

请求方法

对方法字段的说明如下:

  • GET:从服务器请求文档
  • HEAD:请求关于这个文档的信息,然并不是文档自身
  • POST:从客户端向服务器发送消息
  • PUT:服务器向客户端发送文档
  • TRACE:回显服务器收到的请求,主要用于测试或诊断
  • CONNECT:预留给能够将连接改为管道方式的代理服务器
  • DELETE:删除Web网页
  • OPTIONS:询问可用的选项

URL就是在浏览器中提交的地址信息,版本则是http1.1

请求首部行(也称为请求头)

注意到首部行中可以包含多个行,每个首部行都是首部名称与值的组合,那么首部名称有哪些呢?

  • Accept:给出客户能够接收的媒体类型。例如Accept: text/plain, text/html
  • User-agent:标志客户程序的相关信息。例如User-Agent: Mozilla/5.0 (Linux; X11)
  • Accept-Charset:给出客户能够接受的字符集。例如Accept-Charset: iso-8859-5
  • Accept-Encoding:给出客户能够处理的编码方案。例如Accept-Encoding: compress, gzip
  • Accept-Language:给出客户能够接受的语言类型。例如Accept-Language: en,zh
  • Authorization:HTTP授权的授权证书。例如Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
  • Host:给出主机地址和端口号。例如Host: www.baidu.com
  • Upgrade:指明优先使用的通信协议(如果支持的话)。例如Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
  • Cookie:把Cookie回送给服务器。例如Cookie: $Version=1; Skin=new;
  • If-Modified-Since:如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。例如If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
  • Connection:表示是否需要持久连接。(HTTP 1.1默认进行持久连接)。例如Connection: close表示不使用长连接
  • Cache-Control:指定请求和响应遵循的缓存机制。例如Cache-Control: no-cache表示不使用缓存
  • Content-Length:请求的内容长度
  • Content-Type:请求的与MIME对应的类型。例如Content-Type: application/x-www-form-urlencoded
  • Pragma:用来包含实现特定的指令

请求实体

这里面的内容就是客户端实际请求的内容了,通常是一些备注信息

http响应

响应就是服务器给客户端发送的数据,是根据请求而来的。这一点http比较死板,因为没有收到来自客户单的请求,服务器就不会主动给客户端发送响应数据。一个标准的响应报文通常包括状态行、响应首部行、空行和响应主体构成。下面是一个标准的HTTP响应报文模板

状态行

状态行由三个字段构成:版本号标示了当前使用的HTTP协议的版本目前是http1.1,状态码由三位的十进制数字构成,后面会详细说明各个状态码的意义,短语是状态码的补充说明信息。在HTTP协议1.1版本中,共有5类41个状态码,下面是一些常用的状态码:

  • 1** 信息,服务器收到请求,需要请求者继续执行操作
  • 2** 成功,操作被成功接收并处理
  • 3** 重定向,需要进一步的操作以完成请求
  • 4** 客户端错误,请求包含语法错误或无法完成请求
  • 5** 服务器错误,服务器在处理请求的过程中发生了错误

下面是常见状态码的补充说明:

  • 100:短语是Continue。请求的开始部分已经收到,客户可以继续它的请求
  • 101:Switching protocol。服务器同意切换协议,只能切换到更高版本的协议
  • 200:OK。请求成功
  • 201:Created。成功请求并创建了新的资源
  • 202:Accepted。已接受请求,但是还没有处理完成
  • 203:Non-Authoritative Information,非授权信息。请求成功,但返回的meta信息不在原始的服务器,而是一个副本
  • 204:No Content。无内容,服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
  • 301:Move Permanently。永久重定向,请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
  • 302:Found。临时移动。与301类似,但资源只是临时被移动。客户端应继续使用原有URI
  • 304:Not Modified。未修改,所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
  • 400:Bad Request。客户端请求的语法错误,服务器无法理解
  • 401:Unauthorized。请求要求用户的身份认证
  • 403:Forbidden。服务器理解请求客户端的请求,但是拒绝执行此请求
  • 404:Not Found。未找到,服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
  • 405:Method Not Allowed。客户端请求中的方法被禁止
  • 406:Not Acceptable。服务器无法根据客户端请求的内容特性完成请求
  • 500:Internal Server Error。服务器内部错误,无法完成请求
  • 501:Not Implemented:服务器不支持请求的功能,无法完成请求
  • 503:Service Unavailable。由于超载或系统维护,服务器暂时的无法处理客户端的请求。

响应首部行

  1. Date:给出当前日期
  2. Upgrade:指明优先使用的协议(如果可用的话)
  3. Server:给出服务器的相关信息。例如Server: Apache/1.3.27 (Unix) (Red-Hat/Linux)
  4. Set-Cookie:设置http Cookie。例如Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
  5. Accept-Ranges:服务器可接受的字节范围
  6. Last-Modified:请求的资源的最后修改时间。例如Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
  7. ETag:请求变量的实体标签的当前值。例如ETag: “737060cd8c284d8af7ad3082f209582d”
  8. Expires:响应过期的日期和时间
  9. Location:请求客户将请求发送另一个站点。例如Location: http://www.zcmhi.com/archives/94.html
  10. Cache-Control:缓存机制的类型
  11. Content-Encoding:web服务器支持的返回内容压缩编码类型。
  12. Content-Language:响应体的语言
  13. Content-Length:响应体的长度
  14. Content-Type:返回内容的MIME类型

响应主体

如果不是错误的报文,这里的内容是服务器给客户端发送的文档

由于HTTP是基于TCP协议的,所以当我们输入一个网址按回车后,也会经历三次握手,然后开始传输数据。TCP的三次握手已经在前面的文章详细介绍了,这里就不再赘述,这里要说的是长连接(在TCP/IP协议族中叫持续连接,都一样)。长连接通过在Connection设置值为keep-alive就可以实现长连接,不过由于在HTTP1.1的版本中已经默认支持了,所以设置也是多余,但是经过抓包发现,虽然是默认支持的,但是请求头中仍然保留了这个设置。使用长连接后,客户端与服务器可以在同一条连接中操作多个事务,提高传输的效率,同时也降低了资源的开销。

Cookie

Cookie是由服务器创建并保存在客户端的小文件,其内容通常是键值的形式。其主要解决的是http协议无状态这一问题的,通过使用cookie,每次客户端的请求都会把cookie的信息发给服务器,由于cookie文件本来就是由服务器创建的,所以如果发现客户端的请求已经在cookie中出现过,那么就会从cookie中发送响应给客户端,这样就相当于记住了这个请求,还是上面的例子,我们以登陆淘宝网为例,看看cookie是怎么运行的:

下面是我第二次登陆淘宝产生的请求报文:

POST /member/request_nick_check.do?_input_charset=utf-8 HTTP/1.1
x-requested-with: XMLHttpRequest
Accept-Language: zh-cn
Referer: https://login.taobao.com/member/login.jhtml
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: login.taobao.com
Content-Length: 822
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: _umdata=AEEAFDDAE83E4B00CA26803C9421B97EAE678B97A4115D92D89F741A086801F18EEF2C6E67DABD4A9190B085E75633A9F934D879D43962A8B0382F45BAC9B5426DA54C37E8208E0C; lid=%E6%84%A4%E6%80%92%E7%9A%84%E5%86%AC%E8%87%B3%E9%A5%BA00; lc=Vy0WoxbX7NpINANgekCtYw%3D%3D; v=0; cookie2=2c2bbad4a87b1888fab6a665d85a8707; _tb_token_=ggD20qBz0u0pkz3; uc1=cookie14=UoWzXcxBeVjymA%3D%3D&existShop=false&cookie16=WqG3DMC9UpAPBHGz5QBErFxlCA%3D%3D&cookie21=W5iHLLyFeYZ1WM9hVnmS&tag=2&cookie15=URm48syIIVrSKA%3D%3D&pas=0; existShop=MTQ0NDgxMDE4Mw%3D%3D; sg=062; cookie1=B0OqfY0RHVr%2FOcx9qBvroWb9XgI8Di0Qd%2BuC3PoFnEk%3D; unb=1863540266; skt=1baf89c3fabaf276; _l_g_=Ug%3D%3D; _nk_=%5Cu6124%5Cu6012%5Cu7684%5Cu51AC%5Cu81F3%5Cu997A00; cookie17=UondFzxqdRam2Q%3D%3D; t=1e9865b82d621d88c434e1eafa0e3756; cna=kPukDggEeVQCAbfPvQ7eJp+f; isg=0A6DCA6FDD8F2080179659CB403CD682; l=AoaGaE8yxBlkra71oB90h7kflnIJc8qj; thw=cn; uc3=nk2=1BgxApbvq5DWyJqZEM8%3D&id2=UondFzxqdRam2Q%3D%3D&vt3=F8dASMh8gmM6QZZWUV8%3D&lg2=U%2BGCWk%2F75gdr5Q%3D%3D; lgc=%5Cu6124%5Cu6012%5Cu7684%5Cu51AC%5Cu81F3%5Cu997A00; tracknick=%5Cu6124%5Cu6012%5Cu7684%5Cu51AC%5Cu81F3%5Cu997A00; mt=ci=51_1; _cc_=UIHiLt3xSw%3D%3D; tg=0

username=&ua=244UW5TcyMNYQwiAiwQRHhBfEF8QXtHcklnMWc%3D%7CUm5OcktyS35Cf0B%2BR35Cfig%3D%7CU2xMHDJxPk82UjVOI1h2VnhNY0NtMVA2Wj1DORdBFw%3D%3D%7CVGhXd1llXGVcaVVoV2lQaVVpXmNBfkJ3T3FIfEV5RHtOcUV4TGI0%7CVWldfS0SMgk8HCAVNRs%2FUyJRYVF1UWwdI057DjMPMQgmcCY%3D%7CVmNDbUMV%7CV2NDbUMV%7CWGRYeCgGZhtmH2VScVI2UT5fORtmD2gCawwuRSJHZAFsCWMOdVYyVTpbPR99HWAFYU9vQW85bw%3D%3D%7CWWdHFyMdPQAgHCQeKgo%2FCzMTLxQpFDQAPQAgHCcaJwcyCTRiNA%3D%3D%7CWmZYeCgGWjtdMVYoUn5EakpkOHs%2FEy8bOwYmGzsEOQMtey0%3D%7CW2FBET9%2FK28OZQZVaVBpUGVZZFtkX2FZZ0lpVHRMeS95%7CXGZGFjhnPHouUihFPlgxVDltUX9fY0N7TxlP%7CXWFcfFICPQA8ADgYT2FdZF1kUW1QbFBlUGVRJBk7AToDOgU6ATsHPQI3AjYKXXNTbzkXQQ%3D%3D%7CXmZGFjgWNmZaZ1xjQ39Aey0NMBA%2BEDAPMAwwZjA%3D%7CX2VFFTtkP3ktUStGPVsyVzpuUnxcYUF%2BQX5CFEI%3D%7CQHpaCiQKKhY2CTYINGI0%7CQXhFeFhlRXpaZl9jQ31Ff19nU3NJcVFtUWhIdFRoU25OcERkWm9Pek9vU2xMckpqVG07

下面是服务器返回的响应报文:

HTTP/1.1 200 OK
Server: Tengine
Date: Wed, 14 Oct 2015 08:10:46 GMT
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 18
Connection: keep-alive
S: STATUS_NORMAL
X-Category: 
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
Pragma: no-cache
Cache-Control: no-store

{"needcode":false}

从上面的响应报文中可以发现响应体并没有内容,那返回的内容是哪里来的呢?自然是从Cookie中获取并发送给浏览器的。通过这个实例可以发现服务器通过在客户端存储Cookie达到记住客户的目的,从而大大提高了网站的响应速度。还有一点,Cookie并不是与具体的web页面关联的,Cookie只与网站关联,所以在一个网站的每个页面的不同操作如果在用户没有禁止Cookie的情况下,服务器会把所有的操作都记录在Cookie文件中,如果客户的操作记录不在Cookie中,服务器会把新的操作记录更新到Cookie文件中,只要Cookie文件没有过期,网站就会记住你在这个网站的所有操作记录或者叫点击记录

现在已经知道Cookie是通过在客户端保存用户信息来达到服务器记住用户的目的的,还有一种通过把客户信息保存在服务器的方式记住客户的方法,这就是Session

Session

客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。Session对象也是客户端在第一次请求服务器创建的,Session对象的存储形式也是键值对,在服务器可以通过request.getSession().setAttribute(“name”,”value”)设置Session,而在客户端可以通过request.getSeesion().getAttribute(“name”)的方式获取session的value。虽然Session是保存在服务器端的,但是也需要客户端浏览器的支持,http协议由于是无状态的,所以Session对象不能TCP连接就确认是否是同一个客户,所以服务器向客户端发送一个名为JSESSIONID的Cookie并保存在客户端,value就是HttpSession.getId()方法返回的值,这样在客户端就保存了该Session对象Session id。该Session id的值的有效期仅对当前浏览器有效,因为更具体的说Session id的值是保存在内存中的,所以关闭浏览器Session id就会失效。因为Session从语义上理解就是回话的意思,所以会话结束Session自然就失效了。但要注意的是,尽管Session仅对当前浏览器有效,但是对从当前窗口打开的子窗口仍然是有效的,就是说父子页面之间的Session对象是可以共享的。

Session对象和Cookie一样也是有有效期的,从上面已经知道在同一个浏览器打开两个窗口会产生两个Session,那么如果打开的窗口越来越多肯定占用的内存会越来越大,而长期不活跃的Session不及时删除的话就很容易造成内存溢出。Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取超时时间,通过setMaxInactiveInterval(longinterval)修改。这个超时时间就保证了不活跃的Session会被及时删除,降低发生内存溢出的可能性。

你可能感兴趣的:(网络协议系列____HTTP(2))