HTTP 协议
HTTP 是 Hyper Text Transfer Protocol(超文本传输协议)的缩写。它的发展是万维网协会(World Wide Web Consortium)和 Internet 工作小组 IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的 RFC,RFC 1945 定义了 HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616 定义了今天普遍使用的一个版本 —— HTTP 1.1。
HTTP 协议是用于从 WWW 服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。
HTTP 是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP 是一个无状态的协议。详细介绍
HTTP/1.1 协议 Header 详解
通常 HTTP 包含 Request请求消息 和 Response响应消息 两种消息。这两种消息都是由一个起始行、一个或多个头域、一个代表头域结束的空行和可选的消息体组成。例如下面是一个 Request 请求消息:
# 下面是起始行
GET http://arch-long.cn/2017/10/%E7%88%AC%E8%99%AB-Web%E5%9F%BA%E7%A1%80/ HTTP/1.1
# 下面是多个头域
Host: arch-long.cn
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Proxy-Authorization: Basic emhhbmdfcWlhbmdfbmV1OjNlZGMjRURD
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://arch-long.cn/post_list/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
If-Modified-Since: Fri, 27 Oct 2017 07:44:37 GMT
# 下面是代表头域结束的空行
头域分为 通用头域、请求头域、响应头域 和 实体头域 四种。每个头域由一个域的名称、冒号和域值三部分组成,[例如: Referer(域名):(冒号)http://download.google.com/(域值)]。域名是大小写无关的,域值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格和制表符。
- 通用头域 是客户端和服务器都可以使用的头部,可以在客户端、服务器和其他应用程序之间提供一些非常有用的通用功能,如Date头部。
- 请求头域 是请求报文特有的,它们为服务器提供了一些额外信息,比如客户端希望接收什么类型的数据,如Accept头部。
- 响应头域 便于为客户端提供信息,比如,客服端在与哪种类型的服务器进行交互,如Server头部。
- 实体头域 指的是用于应对实体主体部分的头部,比如,可以用实体头部来说明实体主体部分的数据类型,如Content-Type头部。
通用头域
Request 请求消息和 Response 响应消息都支持的头域。通用头域包含 Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。对通用头域的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头域,一般将会作为实体头域处理。
Cache-Control
指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control 并不会修改另一个消息处理过程中的缓存处理过程。请求时的缓存指令包括 no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached,响应消息中的指令包括 public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。例如:Cache-Control: no-cache
值 | 含义 |
---|---|
no-cache | 指示请求或响应消息不能缓存,实际上是可以存储在本地缓存区中的,只是在与原始服务器进行新鲜度验证之前,缓存不能将其提供给客户端使用。 |
no-store | 缓存应该尽快从存储器中删除文档的所有痕迹,因为其中可能会包含敏感信息。 |
max-age | 缓存无法返回缓存时间长于max-age规定秒的文档,若不超规定秒浏览器将不会发送对应的请求到服务器,数据由缓存直接返回;超过这一时间段才进一步由服务器决定是返回新数据还是仍由缓存提供。若同时还发送了max-stale指令,则使用期可能会超过其过期时间。 |
min-fresh | 至少在未来规定秒内文档要保持新鲜,接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象。 |
max-stale | 指示客户端可以接收过期响应消息,如果指定max-stale消息的值,那么客户端可以接收过期但在指定值之内的响应消息。 |
only-if-cached | 只有当缓存中有副本存在时,客户端才会获得一份副本。 |
Public | 指示响应可被任何缓存区缓存,可以用缓存内容回应任何用户。 |
Private | 指示对于单个用户的整个或部分响应消息,不能被共享缓存处理,只能用缓存内容回应先前请求该内容的那个用户。 |
Connection
表示是否需要持久连接。如果 Web 服务器端看到这里的值为Keep-Alive
,或者看到请求使用的是 HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点, web服务器需要在返回给客户端HTTP头信息中发送一个 Content-Length(返回信息正文的长度)头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。例如:Connection: keep-alive
值 | 含义 |
---|---|
Close | 告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了。 |
Keepalive | 告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求。 |
Keep-Alive | 如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒),如Keep-Alive:300。 |
Date
Date头域表示消息发送的时间,服务器响应中要包含这个头部,因为缓存在评估响应的新鲜度时要用到,其时间的描述格式由RFC822定义。例如,Date:Mon, 31 Dec 2001 04:25:57 GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。例如:Date: Tue, 15 Nov 2010 08:12:31 GMT
Pragma
包含实现特定的指令,最常用的是Pragma:no-cache。在 HTTP/1.1 协议中,它的含义和Cache-Control:no-cache相同。例如:Pragma: no-cache
Transfer-Encoding
WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked)。例如:Transfer-Encoding:chunked
Upgrade
它可以指定另一种可能完全不同的协议,如 HTTP/1.1 客户端可以向服务器发送一条 HTTP/1.0 请求,其中包含值为 HTTP/1.1 的 Update 头部,这样客户端就可以测试一下服务器是否也使用 HTTP/1.1 了。例如:Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
Via
列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用什么协议(和版本)发送的请求。当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面添加 Via 头部,并填上自己的相关信息,当下一个代理服务器 收到第一个代理服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的Via头部,并把自己的相关信息加到后面,以此类推,当 OCS 收到最后一个代理服务器的请求时,检查 Via 头部,就知道该请求所经过的路由。例如:Via:1.0 236-81.D07071953.sina.com.cn:80 (squid/2.6.STABLE13)。例如:Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)
实体头域
实体头域提供了有关实体及其内容的大量信息,从有关对象类型的信息,到能够对资源使用的各种有效的请求方法。总之,实体头部可以告知接收者它在对什么进行处理。请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括信息性头部 Allow、Location,内容头部Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type,缓存头部Etag、Expires、Last-Modified、extension-header。
- Allow: 服务器支持哪些请求方法(如GET、POST等)。例如:Allow: GET, POST
- Location 表示客户应当到哪里去提取文档,用于将接收端定位到资源的位置(URL)上。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。
- Content-Base: 解析主体中的相对URL时使用的基础URL。
- Content-Encoding: 表示请求或响应内容的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的 下载时间。Java的GZIPOutputStream可以很方便地进行 gzip 压缩,但只有 Unix 上的 Netscape 和 Windows 上的 IE 4、IE 5 才支持它。因此,Servlet 应该通过查看 Accept-Encoding头(即request.getHeader(“Accept- Encoding”))检查浏览器是否支持 gzip,为支持 gzip 的浏览器返回经 gzip 压缩的 HTML 页面,为其他浏览器返回普通页面。
- Content-Language: 表示请求或响应内容的语言类型,例如:zh-cn
- Content-Length: 表示请求或响应内容长度。只有当浏览器使用持久 HTTP 连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStram,完成后查看其大小,然后把该值放入Content-Length头,最后通过
byteArrayStream.writeTo(response.getOutputStream()
发送内容。 - Content-Location: 表示请求或响应内容实际所处的位置。
- Content-MD5: 表示请求或响应内容MD5校验和。
- Content-Range: 随部分实体一同发送;标明被插入字节的低位与高位字节偏移,也标明此实体的总长度。
- Content-Type: 表示请求或响应内容属于什么MIME类型,一般只有 post 提交时才需要设置该属性。
- Etag: 就是一个对象(比如URL)的标志值,就一个对象而言,比如一个 html 文件,如果被修改了,其 Etag 也会别修改,所以,ETag 的作用跟 Last-Modified 的作用差不多,主要供 WEB 服务器判断一个对象是否改变了。比如前一次请求某个 html 文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得 ETag 值发送给 WEB 服务器,然后 WEB 服务器会把这个 ETag 跟该文件的当前 ETag 进行对比,然后就知道这个文件有没有改变了。
- Expires: 响应过期的日期和时间。为 0 证明不缓存。例如:Expires: Thu, 01 Dec 2010 16:00:00 GMT
- Last-Modified: WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT.
请求头域
# Request 请求消息的格式如下
MethodSPRequest-URISPHTTP-VersionCRLF
其中 SP 代表空格,CRLF 代表回车。实际是下面的样子:
Method Request-URI HTTP-Version
...
...
- Method 表示对Request-URI所使用的方法,这个字段是大小写铭敏感的,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE。其中GET和HEAD方法都是请求返回Request-URI所标识的信息,区别就是HEAD在响应时可以不返回消息体。POST可以在请求服务器的同时附加上实体信息,例如表单信息。
- Request-URI 遵循URI格式,如果此字段是星号(*),说明请求并用于某个特定的资源地址,而是用于服务器本身
- HTTP-Version 表示支持的HTTP版本。例如HTTP/1.1。
除此之外,请求头还允许客户端向服务器传递关于客户端和请求的附加信息。请求头域可能包含Accept、Accept-Charset、Accept-Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If-Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、 Proxy-Authorization、Range、Referer、User-Agent。对于这些扩展要求通讯双方都支持、如果存在不支持的请求域,一般会将其当成实体头域来处理。
典型的请求消息:
GET http://arch-long.cn/2017/10/%E7%88%AC%E8%99%AB-Web%E5%9F%BA%E7%A1%80/ HTTP/1.1
Host: arch-long.cn
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Proxy-Authorization: Basic emhhbmdfcWlhbmdfbmV1OjNlZGMjRURD
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://arch-long.cn/post_list/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
If-Modified-Since: Fri, 27 Oct 2017 07:44:37 GMT
- Accept: 指定客户端能够接收的内容类型,内容类型中的先后次序表示客户端接收的先后次序。例如:Accept: text/plain, text/html
- Accept-Charset: 浏览器可以接受的字符编码集。例如:Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
- Accept-Encoding: 指定客户端浏览器可以支持的web服务器返回内容压缩编码类型。表示允许服务器在将输出内容发送到客户端以前进行压缩,以节约带宽。而这里设置的就是客户端浏览器所能够支持的返回压缩格式。例如:Accept-Encoding: gzip,deflate
- Accept-Language: 指定HTTP客户端浏览器用来展示返回信息所优先选择的语言。例如:Accept-Language: zh-cn,zh;q=0.5
- Authorization: HTTP授权的授权证书。例如:Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
- Cookie: HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。例如:Cookie: $Version=1; Skin=new;
- From: 发出请求的用户的Email。例如:From: [email protected]
- Host: 指定请求资源的Internet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。
- If-Match: 只有请求内容与实体相匹配才有效。例如:If-Match: “737060cd8c284d8af7ad3082f209582d”
- If-Modified-Since: 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。例如:If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT
- If-None-Match: 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变。例如:If-None-Match: “737060cd8c284d8af7ad3082f209582d”
- If-Range: 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag。例如:If-Range: “737060cd8c284d8af7ad3082f209582d”
- If-Unmodified-Since: 只在实体在指定时间之后未被修改才请求成功。例如:If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT
- Max-Forwards: 限制信息通过代理和网关传送的时间。例如:Max-Forwards: 10
- Proxy-Authorization: 连接到代理的授权证书。例如:Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
- Range: 可以请求实体的一个或者多个子范围。如:bytes=0-499表示头500个字节,bytes=500-999 表示第二个500字节,bytes=-500 表示最后500个字节,bytes=500- 表示500字节以后的范围,bytes=0-0,-1 表示第一个和最后一个字节,bytes=500-600,601-999 表示同时指定几个范围。服务器可以忽略此请求头,如果无条件的GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200(OK)。
- Referer: 这个字段的正确拼写是Referrer,由于早期HTTP规范的拼写错误,为了保持向后兼容就将错就错了。当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器当前的请求是从哪个页面链接过来的,服务器藉此可以获得一些信息用于处理。比如从我主页上链接到一个朋友那里,他的服务器就能够从HTTP Referer中统计出每天有多少用户通过我的主页上的链接访问他的网站。例如:Referer: http://www.zcmhi.com/archives/71.html
- TE: 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息。例如: TE: trailers,deflate;q=0.5
- User-Agent: 发出请求的客户端的信息(浏览器信息)。例如:User-Agent: Mozilla/5.0 (Linux; X11)
响应头域
# Response 响应消息的格式如下
HTTP-VersionSPStatus-CodeSPReason-PhraseCRLF
其中SP代表空格,CRLF代表回车 下面的样子:
HTTP-Version Status-Code Reason-Phrase
...
...
Status-Code
是一个三位数的结果代码。可以分为5种。
状态码 | 介绍 |
---|---|
1xx | 信息状态码。表示该请求已经被接受,正在被处理 |
2xx | 正确状态码。表示该请求已经被接受并处理,且没有错误发生。例如200(OK)表示一切正常。 |
3xx | 重定向状态码。例如301、302表示该资源已经不存在或者换了地址,客户端需要重新定向到一个信的资源。服务器响应中会附带这个新资源地址。 |
4xx | 请求错误。401表示没有权限访问、404表示资源不存在、405表示访问方式错误(例如Servlet只接受GET和POST,但是客户端却以DELETE方式访问) |
5xx | 服务器错误。例如500表示程序出现异常而中途停止运行。 |
Reason-Phrase
主要用于帮助用户理解。
除此之外,响应头还允许服务器传递无法放在状态行的附加信息,它们主要描述服务器的信息和Request-URI进一步的信息。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry-After、Server、Vary、Warning、WWW-Authenticate。对响应头域的扩展要求通讯双方都支持,如果存在不支持的响应头域,一般将会作为实体头域处理。
典型的响应消息:
HTTP/1.1 304 Not Modified
Date: Fri, 27 Oct 2017 07:46:40 GMT
Via: 1.1 varnish, 1.1 websense.com
Cache-Control: max-age=600
Expires: Fri, 27 Oct 2017 07:55:21 GMT
Age: 0
X-Served-By: cache-hkg17920-HKG
X-Cache: HIT
X-Cache-Hits: 1
X-Timer: S1509090400.470182,VS0,VE231
Vary: Accept-Encoding
X-Fastly-Request-ID: 377476ee6decbc4f8234514363355a674a326a8f
Proxy-Connection: close
- Accept-Ranges: 表明服务器是否支持指定范围请求及哪种类型的分段请求。例如:Accept-Ranges: bytes
- Age: 从原始服务器到代理缓存形成的估算时间(以秒计,非负)。例如:Age:12
- Allow: 服务器支持哪些请求方法(如GET、POST等)。例如:Allow: GET, POST
- Proxy-Authenticate: 它指出认证方案和可应用到代理的该URL上的参数。例如:Proxy-Authenticate: Basic
- Public:
- Retry-After: 如果实体暂时不可取,通知客户端在指定时间之后再次尝试。Retry-After: 120
- Server: WEB 服务器表明自己是什么软件及版本等信息。例如:Server:Apache/2.0.61 (Unix)
- Vary: WEB服务器用该头部的内容告诉 Cache 服务器,在什么条件下才能用本响应所返回的对象响应后续的请求。假如源WEB服务器在接到第一个请求消息时,其响应消息的头部为:Content-Encoding: gzip; Vary: Content-Encoding,那么Cache服务器会分析后续请求消息的头部,检查其Accept-Encoding,是否跟先前响应的Vary头部值一致,即是否使用相同的内容编码方法,这样就可以防止Cache服务器用自己Cache 里面压缩后的实体响应给不具备解压能力的浏览器。例如:Vary:Accept-Encoding。
- Warning: 警告实体可能存在的问题。Warning: 199 Miscellaneous warning
- WWW-Authenticate: 表明客户端请求实体应该使用的授权方案。WWW-Authenticate: Basic
会话跟踪
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户访问网站的的整个会话。常用的跟踪技术是Cookie和Session。Cookie是将信息记录在客户端、而Session是将信息记录在服务器端。他们的最终目的还是用来确认用户身份。
Cookie
理论上,一个用户的所有请求应该属于同一个会话,两个用户的请求不能混淆。例如用户阿三在超市买的东西只能放到阿三的购物车里,而不能放到用户二麻的购物车里。
Web程序使用HTTP协议传输数据,而HTTP协议是无状态的协议。一旦数据完成交换,客户端和服务端的连接就会关闭,再次交换数据就需要重新建立连接。这样服务器就无法从HTTP连接中追踪会话。即阿三在淘宝将一件衣服加入购物车后(一次请求完毕),再去结算购物车的时候(又一次新的请求),服务端就不知道这个请求是谁发送来的了。而要跟踪该会话,就需要引入一种机制来弥补HTTP协议无状态的缺点。Session出现之前,基本上所有的网站都采用Cookie机制。
服务器单从连接上无法知道当前请求的用户身份,咋办呢?当用户第一次请求服务器的时候,服务器会给该用户颁发一个凭证,每人一个,之后访问的必须带上凭证才能访问,这样服务器就能通过凭证来确认当前的请求是谁了。这就是Cookie的原理。
Cookie实际上就是一小段文本信息,一个Cookie对象就是一个key-value属性对。客户端请求服务器的时候,如果服务器需要跟踪用户状态就通过response向客户端颁发一个Cookie保存在客户端。当浏览器再次请求该网站的时候就把请求地址和Cookie一起提交给服务器,服务器会检查Cookie,辨认用户身份。服务器还可已根据需要修改Cookie的内容或者添加新的Cookie。
要查看一个网站的cookie很简单,在浏览器地址栏输入javascript:alert(document.cookie)
就可以了,当然也可以通过浏览器的开发者页面查看请求/响应的header信息,cookie就包含在http header中。
Cookie的常用属性:
属性名 | 介绍 |
---|---|
String name | Cookie的名字,一旦创建就不可以在改了。 |
Object value | Cookie的值。如果是Unicode字符,需要为字符进行编码。如果是二进制数据则需要BASE64编码 |
int maxAge | Cookie失效的时间,单位秒。如果是正数,则在maxAge秒后失效;如果是负数,说明是临时性Cookie,存储在浏览器内存中,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie;如果为0,表示0秒就失效,即删除。默认值是-1 |
boolean secure | 是否是用安全协议传输。包括HTTPS、SSL等,在网络上传输数据之前是否先将数据加密。默认false |
String path | Cookie访问的路径。如果设置为”/sessionWeb/”,则只有contextPath为”/sessionWeb/”或者其子路径下的程序可以访问该Cookie。如果设置为”/”则本域名下所有的contextPath都可以访问。注/意最后一个字符必须是”/” |
String domain | 可以访问该Cookie的域名。例如”.google.com”,那么所有以”google.com”结尾的域名都可以访问该Cookie。注意:第一个字符必须为”.” |
String comment | Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明 |
int version | Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC2109规范 |
Cookie不提供修改删除操作,要修改就要新建一个同name、path、domain的新Cookie将其覆盖。删除某个Cookie就新建一个同name、path、domain的Cookie并将setMax设置成0,添加到response中覆盖原来的Cookie。
Cookie是不可以跨域名的。域名www.google.com的Cookie不会颁发到www.baidu.com。正常情况下同一个一级域名下的两个二级域名如www.google.com和images.google.com也不能交互使用Cookie,因为域名并不完全相同但是设置domain为”.google.com”就可以了。对于完全不同的域名,希望可以共享Cookie,则可以保存两份同name、不同域名,但内容相同的两个Cookie。
Session
Session是另一种记录客户状态的机制,不同的是Cookie是保存在客户端而Session保存在服务器端。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上,这就是Session。客户端浏览器再次访问时只需要从该Session中查找用户状态就可以了。如果说Cookie是验证用户”凭证”来确定客户身份的话,那么Session就是通过检查服务器上的”客户明细表”来确认用户身份。每一个来访者对应一个Session对象,该用户的所有状态信息都保存在这个对象里。Session对象是在客户端第一次请求服务器的时候创建的。Session也是一种key-value的属性对。
Session保存在服务器端,为了获得更高的存取速度,服务器一般把Session放在内存中。每个用户都有一个独立的Session。如果Session过于复杂,当大量客户访问服务器时就有可能导致内存溢出。因此Session的内容要尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意的是:只有在访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。Session生成之后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都会认为该用户的Session活跃(active)了一次。
为了防止内存溢出,服务器会把长时间内没有活跃的Session从内存中删除。这个时间就是Session的超时时间。如果超过了超时时间没有访问过服务器,Session就自动失效了。
Session的常用方法:
属性名 | 介绍 |
---|---|
void setAttribute(String attribute, Object value) | 设置Session属性 |
String getAttribute(String attribute) | 返回Session中存在的属性名 |
Enumeration getAttributeNames() | 返回Session中的属性名 |
void removeAttribute(String attribute) | 删除Session属性 |
String getId() | 返回Session的ID。由服务器创建,不会重复 |
long getCreateTime() | 返回Session创建的日期,long类型 |
long getLastAccessedTime() | 获取最后一次活跃的时间 |
int getMaxInactiveInterval() | 返回Session的超时时间。单位为秒 |
void setMaxInactiveInterval(int second) | 设置Session的超时时间。单位为秒 |
boolean isNew() | 返回该Session是否是新创建的 |
void invalidate() | 使该Session失效 |
Tomcat中Session默认超时时间为20分钟。可以修改web.xml改变Session的默认超时时间。流入修改为60分钟。
<session-config>
<!-- 单位分钟 -->
<session-timeout>60</session-timeout>
</session-config>
虽然 Session 保存在服务器端,但是对于客户端是透明的,它的正常运行仍然需要客户浏览器的支持。主要是因为 Session 需要使用 Cookie 作为识别标识。HTTP 是无状态的,Session 不能依据 HTTP 连接来判断是否是同一个用户,因此服务器向客户端浏览器发送一个名为 JSESSIONID 的 Cookie,它的值为该 Session 的 id,Session 依据该 Cookie 来识别是否为同一用户。该 Cookie 是服务器自动生成的,他的 maxAge 属性是-1,仅当前浏览器有效,关闭浏览器就失效,因此 Session 在关闭浏览器后也就相当于失效了,所以 Session 不能实现信息永久有效的效果。对于不是双击浏览器桌面图标新开的窗口,即在浏览器已经打开的情况下,然后新开的子窗口,与父窗口共享 Session。而双击桌面浏览器图标打开的新的窗口,浏览器会生成新的 Session。
对于客户端浏览器禁用或者不支持 Cookie 的情况,可以使用 URL 地址重写的方式解决。原理是将该用户的 SessionId 重写到 URL 地址中。
Session 不能跨域名,只能在当前域名内有效。