HTTP初识
- HTTP协议是超文本传输协议(Hyper Text Transfer Protocol)的缩写,是用于从万维网(www)服务器传输超文本到本地浏览器的传送协议;
- 现在万维网使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行中;
- HTTP是一个应用层协议,基于传输层的TCP协议,由请求和响应构成;
- HTTP默认端口号是80,HTTPS的默认端口号是433;
- HTTP协议工作与客户端-服务端(C/S)架构,浏览器作为HTTP客户端通过URL向服务端(Web服务器)发送请求;服务端接受到请求后,向客户端发送响应信息。
HTTP特点
- 支持B/S(浏览器/服务端)和C/S(客户端/服务端)模式;
- 简单快速:客户端向服务端请求服务是,只需要传送请求方法和路径,常用的请求方法:GET、POST、HEAD,由于HTTP协议简单,使得HTTP服务器的程序规模小,所以通信速度快;
- 灵活:允许传输任意类型的数据对象,用Content-Type去进行标记;
- 无连接:限制每次连接至处理一个请求,在完成客户端的请求之后,就断开连接;
- 无状态:指协议对事物处理没有记忆能力,如果后续处理需要前面的信息,则需要重传,这样会导致数据量增大;相反,如果不需要前面的信息,则反应速度更快;
备注(无状态协议)
HTTP协议是一种不保存状态的协议,即无状态(stateless)协议。新的请求发送就会有新的响应产生,协议本身不保留之前的请求或响应报文信息。但是随着业务的发展,很多场景需求中都需要掌握之前报文中的信息,例如电商购物网站,登录之后跳转到该站其他页面,也需要保持登录。HTTP/1.1本身是无状态协议,于是为了满足业务需求,网景通信公司开发来了Cookie并制定了标准,这套标准进行扩展之后的产物就是我们现在常用的管理服务器和客户端之前状态的Cookie。
注意:HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP是用的事UDP协议(无连接),从HTTP/1.1开始,默认都开启了Keep-Alive,保持连接特性,当一个网页打开后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器的网页,会继续使用这条已经建立的连接。但是Keep-Alive有一个保持时间,可以在不同的服务器软件中设定。
Cookie
Cookie会根据从服务器端发送的响应报文内的Set-Cookie首部字段通知客户端保存Cookie。下次客户端再往该服务器发送请求的时候,客户端会自动在请求报文中加入Cookie值后发送出去。
为Cookie服务的首部字段
首部字段名 | 说明 | 首部类型 |
---|---|---|
Set-Cookie | 开始状态管理所使用的Cookie信息 | 响应首部字段 |
Cookie | 服务器收到的Cookie信息 | 请求首部字段 |
Cookie: sid=1324343545
首部字段Cookie会告知服务器,当客户端想获得HTTP状态管理支持时,就会在请求中包含从服务器收到的Cookie,接收到多个Cookie是,同样以多个Cookie形式发送。
Set-Cookie
字段属性
属性 | 说明 |
---|---|
NAME=VALUE | 赋予Cookie的名称和其值(必须) |
expires=DATE | Cookie的有效期(默认为浏览器关闭前为止) |
path=PATH | 将服务器上的文件目录作为Cookie的使用对象(默认为文档所在的文件目录) |
domain=域名 | 作为Cookie适用对象的域名(默认为创建Cookie服务器的域名) |
Secure | 仅在HTTPS安全通信时才会发送Cookie |
HttpOnly | 加以限制,使Cookie不能被JavaScript脚本访问 |
会话跟踪
会话:客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程;
会话跟踪:指对同一个用户对服务器的连续请求和接受响应的监视;
会话跟踪常用的方法:
方法 | 说明 |
---|---|
URL重写 | URL(统一资源定位符)是Web上特定页面的地址,URL重写的技术就是在URL结尾添加一个附加数据以标识该会话,把会话ID通过URL的信息传递过去,以便在服务器端进行识别不同的用户 |
隐藏表单域 | 将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示 |
Cookie | Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用。 客户端可以采用两种方式来保存这个Cookie对象,一种方式是保存在客户端内存中,称为临时Cookie,浏览器关闭后这个Cookie对象将消失。另外一种方式是保存在客户机的磁盘上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器上,前提是这个Cookie在有效期内,这样就实现了对客户的跟踪。 Cookie是可以被禁止的。 |
Session | 每一个用户都有一个不同的session,各个用户之间是不能共享的,是每个用户所独享的,在session中可以存放信息。 在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象,然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户。 Session的实现依赖于Cookie,如果Cookie被禁用,那么session也将失效。 |
Cookie和Session的不同点:
- Cookie将状态保存在客户端,Session将状态保存在服务器端;
- Cookie是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器,Session并没有在HTTP协议中定义;
- Session是针对每一个用户的,变量值保存在服务器上,用一个SessionId来区分是哪个用户,这个是通过用户的浏览器在访问的时候返回给服务器的,当客户金庸cookie时,这个值也可能设置由get返回给服务器;
- 当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些。因为它不会任意读取客户存储的信息。
HTTP报文结构
HTTP请求
URL和URI:
URI:统一资源定位符(Uniform Resource Identifiers),用来唯一标识一个资源。
URI一般由三个部分组成:
1. 访问资源的命名机制
2. 存放资源的主机名
3. 资源自身的名称,由路径表示,着重强调于资源
URL:统一资源定位器(Uniform Resource Locator,是一种具体的URI,即URL可以用来标识一个资源,并且还指明如何定位这个资源;
URL一般由三部分组成:
1. 协议(服务方式)
2. 存有该资源的主机IP地址(域名,有时也包括端口号)
3. 资源的具体地址(根目录)
URL格式:http://host[":port"][path]
1. http表示要通过HTTP协议去定位网络资源;
2. host表示合法的主机域名或者IP;
3. port用来指定访问的端口号,若没有则是用缺省端口80;
4. path指定请求资源的URI,若没有URI,那么必须以“/”的形式来表示。
例: http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name
名称 | 示例 | 解释 |
---|---|---|
协议部分 | http: | 代表网页使用的是HTTP协议 |
域名部分 | www.aspxfans.com | 域名部分也可以使用服务器的IP地址表示 |
端口部分 | 8080 | 域名和端口之间使用":"分隔,端口不是URL必须的,如果没有端口则使用默认80端口 |
虚拟目录部分 | /news/ | 从域名后的第一个"/"到最后一个"/",也不是必须的 |
文件名部分 | index.asp | 从域名后的最后一个"/"到"?",如果没有"?",则到“#”,如果都没有,则一直到最后 |
锚部分 | name | 从"#"开始到最后 |
参数部分 | boardID=5&ID=24618&page=1 | 在"?"到"#"之间的部分,允许有多个参数,参数之间用"&"分隔 |
URN:统一资源命名(uniform resource name),是通过名字来标识资源。
总结:URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。笼统地说,每个 URL 都是 URI,但不一定每个 URI 都是 URL。这是因为 URI 还包括一个子类,即统一资源名称 (URN),它命名资源但不指定如何定位资源。
在Java的URI中,一个URI实例可以代表绝对的,也可以是相对的,只要它符合URI的语法规则。而URL类则不仅符合语义,还包含了定位该资源的信息,因此它不能是相对的。
在Java类库中,URI类不包含任何访问资源的方法,唯一的作用就是解析,而URL类可以打开一个到达资源的流。
HTTP请求组成:开始行[请求行]、[消息报头]、(空行CR+LF)、[请求正文]
请求行:包括请求方法,请求的URI,HTTP协议版本号[例如:POST /xxx HTTP/1.1]
常见的请求方法(请求类型)
请求方法名称(使用) | 请求方法解释(特征) |
---|---|
GET | 请求获取Request-URI所标识的资源 |
POST | 在Request-URI所标识的资源后附加的新的数据 |
HEAD | 请求获取由Request-URI所标识的资源的响应消息报头 |
PUT | 请求服务器存储一个资源,并用Request-URI作为标识 |
DELETE | 请求服务器删除Request-URI所标识的资源 |
TRACE | 请求服务器发送收到的请求信息,用于测试或诊断 |
CONNECT | 保留 |
OPTIONS | 请求查询服务器的性能,或者查询与资源相关的选项和需求 |
消息头:常用头、请求头、响应头、实体头
Request-Headers
key(大小写不敏感) : value
消息主体和实体主体
消息主体(message-body):客户端想让服务端看到的内容;
实体主体(entity-body):服务端接收到来自客户端的实际内容;
注意:传输过程中,可能会对entity-body进行编码;而且不是所有请求消息或者响应消息都有消息主体。消息主体可否存在由请求类型和响应类型决定;
常见的请求头:(在HTTP/1.1中,所有的请求头,除了Host外,都是可选的)
请求头 | 使用说明 |
---|---|
If-Modified-Since | 允许在对应的资源未被修改的情况下执行并返回304未修改 |
If-Unmodified-Since | 只有请求的对象在指定的时间之后没有修改才执行 |
If-Match | 仅当客户端提供的实体与服务器上对应的实体相匹配时,才进行对应的操作。主要用于像 PUT 这样的方法中,仅当从用户上次更新某个资源后,该资源未被修改的情况下,才更新该资源,对象没有改变才执行请求的动作 |
If-None-Match | If-None-Match和ETag一起工作,工作原理是在HTTP Response中添加ETag信息,对象改变了执行请求 |
If-Range | 浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。总是和Range头部一起使用 |
Last-Modified | Web服务器认为对象的最后修改时间 |
Location | Web服务器告诉浏览器,访问的对象一道别的位置了,到指定的位置去取 |
Accept | 可接受的响应内容类型(MIME-TYPE) |
Accept-Encoding | 浏览器申明自己可接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate) |
Accept-Language | 可接受的响应内容语言列表 |
Accept-Charset | 浏览器可接受的字符集 |
Accept-Agent | 告诉HTTP服务器,客户端使用的操作系统和浏览器的名称和版本 |
Authorization | 授权信息,用于表示HTTP协议中需要认证资源的认证信息,主要用于证明客户端有权查看某个资源 |
Referer | 包含一个URL,用户从该URL代表的页面出发访问当前请求的页面 |
Cache-Control | 指定请求和响应遵循的缓存机制,普通报头,与HTTP1.0的Program类似,请求时的缓存指令包括:no-cache |
Connection | keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭 close 代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭 |
Cookie | 将cookie的值发送给HTTP服务器 |
Content-Length | 表示请求消息正文的长度 |
Content-Type | 请求体的MIME类型 (用于POST和PUT请求中) |
Expect | 表示客户端要求服务器做出特定的行为 |
Host | 表示服务器的域名以及服务器所监听的端口号,如果所请求的端口是对应的服务的标准端口(80),则端口号可以省略,通常从HTTP URL中提取 |
Pramga | 相当于Cache-Control: no-cache |
Range | 可以请求实体的一个或者多个子范围 |
UA-Pixels,UA-Color,UA-OS,UA-CPU | 由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型 |
From | 请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用 |
POST提交数据的方式
- 通过form表单的enctype
enctype值 | 描述 |
---|---|
application/x-www-form-urlencoded | 在发送前编码所有字符(默认) |
multipart/form-data | 不对字符编码 在使用包含文件上传的表单时,必须使用这个类型 |
text/plain | 空格转换为"+"号,但不对特殊字符编码 |
- 通过Content-Type: application/json方式,用来告诉服务端消息主题是序列化后的json字符串
HTTP响应
HTTP响应组成:开始行[状态行]、[响应报头]、(空行CR+LF)、[响应正文]
响应头
响应头 | 使用说明 |
---|---|
Allow | 对于特定资源的有效动作(GET、POST) |
Date | 表示消息的发送时间,例如,Date:Mon,31Dec200104:25:57GMT |
Expires | 指定一个日期/时间,超过该时间则认为此回应已经过期,不再缓存 |
P3P | 用于跨域设置Cookie, 这样可以解决iframe跨域访问cookie的问题 |
Set-Cookie | 设置HTTP cookie,用于把cookie发送到客户端浏览器 |
ETag | 和If-None-Match配合使用,对于某个资源的某个特定版本的一个标识符,通常是一个消息散列 |
Last-Modified | 用于指示资源的最后修改日期和时间 |
Content-Type | 当前响应的对象内容的MIME类型和字符集(Content-Type: text/html;charset=ISO-8859-1) |
Content-Range | 用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度 |
Content-Length | 指明实体正文的长度,以字节方式存储的十进制数字来表示 |
Content-Encoding | WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象 |
Content-Language | 响应对象内容所使用的语言 |
Server | 指明HTTP服务器用来处理请求的软件信息 |
Connection | keep-alive 当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭 close 代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭 |
Location | 用于重定向一个新的位置,包含新的URL地址 |
Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计 |
WWW-Authenticate | 该响应报头域必须被包含在401(未授权的)响应消息中 |
Last-Modified | 指示资源最后的修改日期 |
响应状态码(响应类型)
状态码(描述) | 举例 |
---|---|
1XX(接受的请求正在处理) | |
2XX(请求正常处理完毕) | 200:请求成功 204:服务器已成功处理请求,但是返回的响应报文不包含实体部分 206:GET请求成功后,响应报文的长度受Content-Range影响 |
3XX(重定向状态码,需要进行附加操作) | 301:永久重定向,以后使用响应报文头部中Location定的URL 302:临时重定向,请求的资源有了新的URL,重定向时使用原有请求方法 303:与302一样,但是303表明客户端重定向时应使用GET方法 304:浏览器请求的资源没有更新,可以使用上次获取过的缓存的文件 307:临时重定向 |
4XX(客户端错误,服务端无法处理请求) | 400:请求报文中存在语法错误 401:表示发送的请求需要有通过HTTP(BASIC、DIGEST)认证的认证信息 WWW-Authenticate 403:请求访问被服务器拒绝 404:没有找到请求资源 |
5XX(服务端处理请求错误) | 500:服务器执行请求时报错 503:服务器暂时无法处理请求 |
持久连接
在HTTP协议的初始版本中,每进行一次HTTP通信就要断开一次TCP连接
但是这种方案在请求很多静态资源的时候,就会一直重复这个操作,会造成很多无谓的开销。
为了解决TCP连接问题,出了 持久连接方案 -- 只要任意一端没有明确提出断开连接,就保持TCP的连接状态,如图:
持久连接减少了TCP重复建立和断开所造成的额外开销,减少的重复建立和断开的这部分时间,使HTTP请求和响应能更早的结束,这样页面的显示速度也就快了。
在HTTP/1.0中,并没有官方标准规定Keep-Alive如何工作,因此这个是被附加到HTTP/1.0协议上的,如果客户端浏览器支持Keep-Alive,那么就在HTTP请求头中添加一个字段Connection: Keep-Alive,当服务器收到这样的请求时,则在响应头中也会添加一个同样的字段来使用Keep-Alive,这样,客户端和服务端之间的HTTP连接就会被保持。
在HTTP/1.1中,默认情况所有连接都是持久连接。客户端会在持久连接上连续发送请求。当客户端想断开连接时,则指定Connection为Close。
注意:
- HTTP Keep-Alive就是保持当前的TCP连接,避免重新建立连接;
- HTTP长连接不可能一直保持,例如Keep-Alive: timeout=5, max=100,表示这个TCP通道可以保持5秒,最多接收100次请求就断开;
- HTTP是一个无状态连接,意味着每个请求都是独立的,Keep-Alive唯一能做到的就是当连接被关闭的时候能得到通知;
HTTP管线化
默认情况下 HTTP 协议中每个传输层连接只能承载一个 HTTP 请求和响应,浏览器会在收到上一个请求的响应之后,再发送下一个请求。在使用持久连接的情况下,某个连接上消息的传递类似于请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3。
HTTP Pipelining(管线化)是将多个 HTTP 请求整批提交的技术,在传送过程中不需等待服务端的回应。使用 HTTP Pipelining 技术之后,某个连接上的消息变成了类似这样请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3。
注意:
- 管线化机制通过持久连接(persistent connection)完成,仅 HTTP/1.1 支持此技术(HTTP/1.0不支持)
- 只有 GET 和 HEAD 请求可以进行管线化,而 POST 则有所限制
- 初次创建连接时不应启动管线机制,因为对方(服务器)不一定支持 HTTP/1.1 版本的协议
- 管线化不会影响响应到来的顺序,如上面的例子所示,响应返回的顺序并未改变
- HTTP /1.1 要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可
- 由于上面提到的服务器端问题,开启管线化很可能并不会带来大幅度的性能提升,而且很多服务器端和代理程序对管线化的支持并不好,因此现代浏览器如 Chrome 和 Firefox 默认并未开启管线化支持