本文共 8571 字,大约阅读时间需要 28 分钟。
这篇文章继续对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的基础增加以下特性:
下面就从请求与响应两个角度说明http协议的方方面面
http请求
前面提到http协议(这里介绍的都是基于http1.1版本)请求会发送给一个请求报文,我们从这个请求报文入手,详细说明http请求是什么鬼,下面是一个http请求的模板
其中sp
表示空格,cr
表示回车,lf
表示换行,注意到从请求行到主体,每一行都包括回车和换行,中间的空行是为了区分请求头和请求主体的。空行之前的都是请求头,空行之后的是具体的请求消息主体。
请求方法
对方法字段的说明如下:
URL就是在浏览器中提交的地址信息,版本则是http1.1
请求首部行(也称为请求头)
注意到首部行中可以包含多个行,每个首部行都是首部名陈与值的组合,那么首部名称有哪些呢?
请求实体
这里面的内容就是客户端实际请求的内容了,通常是一些备注信息
http响应
响应就是服务器给客户端发送的数据,是根据请求而来的。这一点http比较死板
,因为没有收到来自客户单的请求服务器就不会主动给客户端发送响应数据。一个标准的响应报文通常包括状态行、响应首部行、空行和响应主体构成。下面是一个标准的HTTP响应报文模板
状态行
状态行由三个字段构成:版本号标示了当前使用的HTTP协议的版本目前是http1.1,状态码由三位的十进制数字构成,后面会详细说明各个状态码的意义,短语是状态码的补充说明信息。在HTTP协议1.1版本中,共有5类41个状态码,下面是一些常用的状态码:
下面是常见状态码的补充说明:
响应首部行
响应主体
如果不是错误的报文,这里的内容是服务器给客户端发送的文档
由于HTTP是基于TCP协议的,所以当我们输入一个网址按回车后,也会经历三次握手,然后开始传输数据。TCP的三次握手已经在前面的文章详细介绍了,这里就不再赘述,这里要说的是长连接(在TCPIP协议族中叫持续连接,都一样)。长连接通过在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.1x-requested-with: XMLHttpRequestAccept-Language: zh-cnReferer: https://login.taobao.com/member/login.jhtmlAccept: application/json, text/javascript, */*; q=0.01Content-Type: application/x-www-form-urlencoded; charset=UTF-8Accept-Encoding: gzip, deflateUser-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)Host: login.taobao.comContent-Length: 822Connection: Keep-AliveCache-Control: no-cacheCookie: _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=0username=&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 OKServer: TengineDate: Wed, 14 Oct 2015 08:10:46 GMTContent-Type: application/x-www-form-urlencoded;charset=UTF-8Content-Length: 18Connection: keep-aliveS: STATUS_NORMALX-Category: Expires: Thu, 01 Jan 1970 00:00:01 GMTCache-Control: no-cachePragma: no-cacheCache-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://mgall.baihongyu.com/