HTTP
TCP/IP
使用的网络是在TCP/IP协议族的基础上运作的。HTTP属于它内部的一个子集。
协议:计算机与设备要互相通信,双方就必须基于相同的方法。这种规则称为协议(protocol)
分层管理
TCP/IP协议族按层次分别分为4层:应用层、传输层、网络层、数据链路层。分层的优点是:单一职责和灵活变动。
应用层:决定向用户提供应用服务时通信的活动,例如:FTP、DNS。HTTP协议也处于该层。
传输层:提供处于网络连接中的两台计算机之间的数据传输。例如:TCP、UDP
网络层:用来处理网络上流动的数据包,规定了通过怎样的路径到达对方计算机。例如:IP协议
链路层:用来处理连接网络的硬件部分,包括操作系统、硬件设备驱动、光纤等物理部件。
发送端顺序从上往下,接收端顺序从下往上。
举例:
首先客户端在应用层发出一个HTTP请求。传输层把收到的HTTP报文进行分割,并标记序号和端口号发给网络层。
网络层(IP协议)增加作为通信目的地的MAC地址后转发给链路层
发送端层与层之间传输数据时,每经过一层则会打上该层所属的首部信息。接收端则经过每层都会把对应信息消除。
IP传输
IP协议的作用是把各种数据包传送给对方,其中有两个条件必须满足:IP地址和MAC地址。
IP地址指明节点被分配到的地址,MAC地址是指网卡所属的固定地址。IP可变,MAC不可变。
IP间的通信依赖MAC地址,通常是经过多台计算机和网络设备中转才能连接到对方。
在中转时,会利用下一站中转设备的MAC地址来搜索下一个中转目标。会采用APR协议。
ARP是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对应的MAC地址。
TCP协议
TCP位于传输层,提供可靠的字节流服务。指将大块数据分割成以报文段为单位的数据包进行管理。
TCP协议为了更容易传送大数据才把数据分割,而且TCP协议能够确认数据最终是否送达到对方。
三次握手
为了准确传送数据,TCP协议采用了三次握手策略。
1. 发送端首先发送一个带有SYN标志的数据包给对方。
2. 接收端收到后,回传一个带有SYN/ACK标志的数据包传达确认信息。
3. 发送端在回传一个带ACK标志的数据包,表示握手结束。
DNS域名解析
跟HTTP协议一样,处于应用层。DNS协议通过域名查找IP地址或从IP地址反查域名。
URI:统一资源标识符。由某个协议方案表示的资源定位标识符
URL:统一资源定位符
Uniform:规定统一的格式方便处理多种不同类型的资源,不用根据上下文环境来识别资源指定的访问方式。
Resource:字符串标志。资源定义是可标识的任何东西。文档、图形、服务
Identifier:可标识的对象。也称为标识符。
采用HTTP协议是,Uniform 就是http。URI用字符串标识某一互联网资源,URL表示资源的地址是URI的子集。
格式:http://(协议名)user:pass(登录信息)@www.example.jp:80(服务器地址和端口号)/index.html(文件路径)?uid=1(查询字符串)@ch1(片段标识符,例如锚点)
HTTP通信
进行HTTP协议通信时,比如一端是客户端,另一端是服务端。必定是客户端发送请求,服务端回复响应。
无状态协议
HTTP是不保存状态的协议:即无状态协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。
持久链接
持久链接特点是:只要任意一端没有明确提出断开链接,则保持TCP链接状态。用来避免频繁创建链接使服务器压力增大。
HTTP/1.1中所有的链接默认都是持久链接。
管线化
持久连接使多数请求以管线化进行发送。可以做到同时并行发送多个请求,不需要一个接一个地等待响应。
压缩传输
HTTP协议中有一种内容编码的功能,指明应用在实体内容上的编码格式,并保存实体信息原样压缩。
内容编码后的实体由客户端接收并负责解码。
常用的内容编码有以下几种:
1. gzip(GNU zip)
2.compress(UNIX系统的标准压缩)
3.deflate(zlib)
4.identity(不进行编码)
分块传输
HTTP通信中编码实体资源尚未完全传输完成之前,浏览器无法显示请求页面。
在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。
把实体主体分块的功能称为分块传输编码。
分块传输编码会将实体主体分成多个部分快,每一块用十六进制来标记块的大小,最后一块使用0来标记。
使用分块传输编码的实体主体会由接受的客户端负责解码,恢复到编码前的实体主体。
HTTP/1.1中存在一种称为传输编码的机制,它可以在通信时按某种编码方式传输,但只定义作用于分块传输编码中。
MIME
MIME机制,允许邮件处理文本、图片、视频等多个不同类型的数据。例如:图片等二进制数据以ASCII码字符串编码的方式,
就是利用MIME来描述标记数据类型。而在MIME扩展中会使用一种称为多部分对象集合的方法,来容纳多份不同类型的数据。
分流下载
如果下载过程中网络中断,就必须从头开始。为了解决问题,需要一种可恢复的机制。可以从之前下载中断处恢复下载。
要实现该功能需要指定下载实体范围。指定范围发送的请求叫做范围请求。
对一份10000字节大小的资源,如果使用范围请求,可以只请求5001-10000字节内的资源。
执行范围请求时,会用到首部资源Range来指定资源的byte范围。例如:
Range:bytes=5001-10000 (从5000-10000)
Range:bytes=5001- (从5001字节之后全部的)
Range:bytes=-3000,5000-7000 (从开始到3000和5000-7000字节)
针对范围请求,响应会返回 206(部分内容)的响应报文。对于多重范围的范围请求,响应在首部字段。
如果无法响应范围请求,则会返回状态码200和完整的实体内容。
内容协商
当浏览器的默认语言为英文时,访问相同的URI和Web页面则会显示对应的英语版的页面。
指客户端和服务端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。
内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。
状态码
状态码中第一位指定了响应类别,后两位无分类。响应类别有如下5中。
1XX:接受的请求正在处理
2XX:请求正常处理完毕
3XX:需要进行附加操作已完成请求
4XX:服务器无法处理请求
5XX:服务器处理请求出错
经常使用的有14中状态码
2XX:请求被正常处理了
200 OK
表示从客户端发来的请求被正常处理了
204 No Content
代表服务器接收的请求以成功处理,但在返回的响应报文中不含实体的主体部分。
比如:发送请求处理后,返回204响应,浏览器不发生更新。
206 Partial Content
客户端进行了范围请求,而服务器成功执行了这部分的Get请求。
响应报文中包含有Content-Range 指定范围的实体内容。
3XX:需要执行某些特殊的处理以正确处理请求
301 Moved Permanently
永久性重定向,表示请求资源已被分配了新的URI。
302 Found
临时性重定向。该状态码表示请求的资源已被分配了新的URI。
303 See Other
请求对应的资源存在着另一个URI,应使用Get方法定义获取请求的资源。
304 Not Modified
不包含任何响应的主体部分。
307 Temporary Redirect
临时重定向,跟302相比,不会从POST变成GET。
4XX:客户端错误
400 Bad Request
请求表文中存在语法错误。需修改请求的内容后再次发送请求。
401 Unauthorized
用户认证失败,没有通过HTTP认证。
403 Forbidden
对请求资源的访问被服务器拒绝了。服务器没有必要给出拒绝的详细理由。
未获取文件系统的访问授权,或从未授权的地址发送IP地址试图访问。都是403的原因。
404 Not Found
无法找到请求的资源
5XX:服务器本身发生错误
500 Internal Server Error
服务器端在执行请求时发生了错误,也有可能是Web应用存在bug或某些临时的故障。
503 Service Unavailable
服务器出超负载或进行停机维护
通信数据转发程序
HTTP通信时,除客户端和服务器外,还有一些用于通信数据转发的程序。
代理
一种有转发功能的应用程序,扮演了位于服务器和客户端“中间人”角色。接受由客户端发送的请求并转发给服务器。
网关
网关是转发其他服务器通信数据的服务器,接受从客户端发来的请求。对请求进行处理。
隧道
隧道是在相隔甚远的客户端和服务器两者之间进行中转,并保存双方通信连接的应用程序。
缓存
缓存指代理服务器或客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问。
缓存服务器是代理服务器的一种,并归类在缓存代理类型中。当代理转发从服务器返回的响应时,会保存一份资源的副本。
优势:利用缓存可避免多次从源服务器转发资源,因此客户端可就近从缓存服务器上获取资源。
有效期
当遇上源服务器上的资源更新时,如果还是使用不变的缓存,那就会变成返回更新前的旧资源了。
因此会因客户端的要求,花奴才能的有效期等因素。源服务器确定缓存的有效性。如失效则会从新获取。
客户端的缓存
缓存还可以存在客户端浏览器中。如果有效就不必向服务器请求相同的资源了,可以从本地直接读取。
当判断缓存国旗后,服务器确定资源的有效性。若浏览器缓存失效,浏览器会再次请求缓存。
HTTP头
HTTP头分为4种
1.通用首部字段
请求报文和响应报文两方都会使用的首部。
2.请求首部字段
补充了请求的附加内容、客户端信息、响应内容相关优先级等信息
3.响应首部字段
补充了响应的附加内容,要求客户端附加额外的内容信息。
4.实体首部字段
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容、更新时间等于实体有关的信息。
详细列表:HTTP头明细说明
HTTPS
一、作用
不使用SSL/TLS的HTTP通信,就是不加密的通信。所有信息明文传播,带来了三大风险。
(1) 窃听风险(eavesdropping):第三方可以获知通信内容。
(2) 篡改风险(tampering):第三方可以修改通信内容。
(3) 冒充风险(pretending):第三方可以冒充他人身份参与通信。
SSL/TLS协议是为了解决这三大风险而设计的,希望达到:
(1) 所有信息都是加密传播,第三方无法窃听。
(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。
(3) 配备身份证书,防止身份被冒充。
互联网是开放环境,通信双方都是未知身份,这为协议的设计带来了很大的难度。而且,协议还必须能够经受所有匪夷所思的攻击,这使得SSL/TLS协议变得异常复杂。
二、历史
互联网加密通信协议的历史,几乎与互联网一样长。
1994年,NetScape公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。
1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。
1996年,SSL 3.0版问世,得到大规模应用。
1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版。
2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。最新的变动是2011年TLS 1.2的修订版。
目前,应用最广泛的是TLS 1.0,接下来是SSL 3.0。但是,主流浏览器都已经实现了TLS 1.2的支持。
TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。
三、基本的运行过程
SSL/TLS协议的基本思路是采用公开密钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。
但是,这里有两个问题。
(1)如何保证公钥不被篡改?
解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。数字证书认证机构CA,双方都可信赖的第三方机构。
使用CA以后的流程变为:
1.服务器向机构提出申请,机构判明申请者身份后,会对已申请的公开密钥证书做数字签名,然后分配这个已签名的公开密钥。
2.服务器会将这份由数字证书认证机构颁发的公钥证书发给客户端,并进行公共密钥加密方式通信。
3.接到证书的客户端可使用数字证书认证机构的公开密钥,对那证书上的签名进行验证。
公开密钥转交给客户端,是一件很困难的事情,因此多数浏览器开发商会在内部植入常用的认证机关的公开密钥。
(2)公钥加密计算量太大,如何减少耗用的时间?
解决方法:每一次对话(session),客户端和服务器端都生成一个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。
因此,SSL/TLS协议的基本过程是这样的:
(1) 客户端向服务器端索要并验证公钥。
(2) 双方协商生成"对话密钥"。
(3) 双方采用"对话密钥"进行加密通信。
上面过程的前两步,又称为"握手阶段"(handshake)。
四、握手阶段的详细过程
"握手阶段"涉及四次通信,我们一个个来看。需要注意的是,"握手阶段"的所有通信都是明文的。
4.1 客户端发出请求(ClientHello)
首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。
在这一步,客户端主要向服务器提供以下信息。
(1) 支持的协议版本,比如TLS 1.0版。
(2) 一个客户端生成的随机数,稍后用于生成"对话密钥"。
(3) 支持的加密方法,比如RSA公钥加密。
(4) 支持的压缩方法。
这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。
对于虚拟主机的用户来说,这当然很不方便。2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。
4.2 服务器回应(SeverHello)
服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
(1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
(2) 一个服务器生成的随机数,稍后用于生成"对话密钥"。
(3) 确认使用的加密方法,比如RSA公钥加密。
(4) 服务器证书。
除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。
4.3 客户端回应
客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
(1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。
(2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
(3) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。
至于为什么一定要用三个随机数,来生成"会话密钥",dog250解释得很好:
"不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"
此外,如果前一步,服务器要求客户端证书,客户端会在这一步发送证书及相关信息。
4.4 服务器的最后回应
服务器收到客户端的第三个随机数pre-master key之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。
(1)编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验。
至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
WEB攻击
Web攻击分为两种:主动攻击和被动攻击
主动攻击:指攻击者通过访问Web应用,把攻击代码传入的攻击模式。例如:SQL注入
被动攻击:指利用圈套策略执行攻击代码的攻击模式。攻击者不直接对目标发起攻击。例如:XSS(跨站脚本攻击)和CSRF(跨站请求伪造)
步骤大致如下:
1.攻击者诱导用户触发已设置好的陷阱,而陷阱会启动发送已嵌入攻击代码的HTTP请求。
2.当用户不知不觉中招后,用户的浏览器或邮件客户端就会触发这个陷阱。
3.中招后的用户浏览器会把含有攻击代码的HTTP请求发送给作为攻击目标的Web应用,运行攻击代码。
4.存在安全漏洞的Web应用会成为攻击者的跳板,可能导致用户所持的Cookie等个人信息被窃取。
跨站脚本攻击
Cross-Site Scripting,XSS:是指通过存在安全漏洞的Web网站注册用户的浏览器运行非法的HTML标签或JavaScript进行的一种攻击。
动态创建的HTML部分有可能隐藏着安全漏洞。攻击者编写脚本设下陷阱,用户在自己的浏览器上运行时,不小心就会受到攻击。
攻击可能造成的影响:
1.利用虚假输入表单骗取用户个人信息。
2.利用脚本窃取用户的Cookie值,被害者在不知情的情况下,帮助攻击者发送恶意请求。
3.显示伪造的文章或图片。
例如:
"UTF-8">Title 姓名:"text" id="txtName" /> "spName">
如上所示,我如果在姓名中输入:。就会执行脚本,进行跳转。
HTTP头明细
通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。客户端向服务器发送一个请求,请求头包含请求的方法、URI、协议版本、以及包含请求修饰符、客户信息和内容的类似于MIME的消息结构。服务器以一个状态行作为响应,相应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。
Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET、POST、PUT、DELETE。一个URL地址用于描述一个网络上的资源,而HTTP中的GET、POST、PUT、 DELETE就对应着对这个资源的查、改、增、删4个操作,我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
HTTP头信息解读
HTTP的头域包括通用头、请求头、响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。
通用头部是客户端和服务器都可以使用的头部,可以在客户端、服务器和其他应用程序之间提供一些非常有用的通用功能,如Date头部。
请求头部是请求报文特有的,它们为服务器提供了一些额外信息,比如客户端希望接收什么类型的数据,如Accept头部。
响应头部便于客户端提供信息,比如,客服端在与哪种类型的服务器进行交互,如Server头部。
实体头部指的是用于应对实体主体部分的头部,比如,可以用实体头部来说明实体主体部分的数据类型,如Content-Type头部。
HTTP通用头
通用头域包含请求和响应消息都支持的头域,通用头域包含缓存头部Cache-Control、Pragma及信息性头部Connection、Date、Transfer-Encoding、Update、Via。
1、Cache-Control
Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置 Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。
缓存请求指令 (指令:参数:说明)
- no-cache:无:强制向源服务器再次验证
- no-store:无:不缓存请求或响应的任何内容
- max-age=[秒]:必需:响应的最大Age值(Age值表示缓存寿命时间)
- max-stale(=[秒]):可省略:接收已过期的响应
- min-fresh=[秒]:必需:期望在指定时间内的响应仍有效
- no-transform:无:代理不可更改媒体类型
- only-if-cached:无:从缓存获取资源
- cache-extension:-:新指令标记(token)
缓存响应指令
- public:无:可向任意方提供响应的缓存
- private:可省:仅向特定用户返回响应
- no-cache:可省:缓存前必须先确定其有效性
- no-store:无:不缓存请求或响应的任何内容
- no-transform:无:代理不可更改媒体类型
- must-revalidate:无:可缓存但必须再向源服务器进行确认
- proxy-revalidate:无:要求中间缓存服务器对缓存的响应进行有效性验证
- max-age:响应最大的Age值
- s-maxage:公共缓存服务器的最大Age值
- cache-extension:-:新指令标记(token)
2、Pragma
Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache- Control:no-cache相同。
3、Connection
Connection表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。
Close:告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了。
Keepalive:告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求。
Keep-Alive:如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒),如Keep-Alive:300。
4、Date
Date头域表示消息发送的时间,服务器响应中要包含这个头部,因为缓存在评估响应的新鲜度时要用到,其时间的描述格式由RFC822定义。例如,Date:Mon, 31 Dec 2001 04:25:57 GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。
5、Trailer
说明在报文主体后记录了哪些首部字段,该字段可应用在分块传输编码时。
5、Transfer-Encoding
WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked),例如:Transfer-Encoding: chunked
6、Upgrade
它可以指定另一种可能完全不同的协议,如HTTP/1.1客户端可以向服务器发送一条HTTP/1.0请求,其中包含值为“HTTP/1.1”的Update头部,这样客户端就可以测试一下服务器是否也使用HTTP/1.1了。
7、Via
列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用什么协议(和版本)发送的请求。
当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面添加 Via 头部,并填上自己的相关信息,当下一个代理服务器 收到第一个代理服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的Via头部,并把自己的相关信息加到后面,以此类推,当 OCS 收到最后一个代理服务器的请求时,检查 Via 头部,就知道该请求所经过的路由。例如:Via:1.0 236-81.D07071953.sina.com.cn:80 (squid/2.6.STABLE13)
7、Warning
Warning首部是从HTTP/1.0的响应首部演变过来的,告知用户一些与缓存相关的警告。一共7种警告:
- 110:代理返回已过期的资源
- 111:代理再验证资源有效性时失败
- 112:代理与互联网连接被故意切断
- 113:响应的使用期超过24小时
- 119:任意的警告内容
- 214:代理对内容编码或媒体类型等执行了某些处理
- 299:持久性的任意警告内容
HTTP请求头
请求头用于说明是谁或什么在发送请求、请求源于何处,或者客户端的喜好及能力。服务器可以根据请求头部给出的客户端信息,试着为客户端提供更好的响应。请求头域可能包含下列字段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。对请求头域的扩展要求通讯双方都支持,如果存在不支持的请求头域,一般将会作为实体头域处理。
8、Accept
告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type。
例如:Accept:text/plain;q=0.3,text/htm。q表示优先级,范围是0-1,使用;进行分割。也就是优先给我html。
9、Accept-Charset
浏览器告诉服务器自己能接收的字符集。
10、Accept-Encoding
浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)。
11、Accept-Language
浏览器申明自己接收的语言。语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等。
12、Authorization
当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器。
13、If-Match
如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作,获取文档。
14、If-None-Match
如果对象的 ETag 改变了,其实也就意味著对象也改变了,才执行请求的动作,获取文档。
15、If-Modified-Since
如果请求的对象在该头部指定的时间之后修改了,才执行请求的动作(比如返回对象),否则返回代码304,告诉浏览器该对象没有修改。例如:If-Modified-Since:Thu, 10 Apr 2008 09:14:42 GMT
16、If-Unmodified-Since
如果请求的对象在该头部指定的时间之后没修改过,才执行请求的动作(比如返回对象)。
17、If-Range
浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。
18、Range
浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。例如:Range: bytes=1173546
19、Proxy-Authenticate
代理服务器响应浏览器,要求其提供代理身份验证信息。
20、Proxy-Authorization
浏览器响应代理服务器的身份验证请求,提供自己的身份信息。
21、Host
客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号。如Host:rss.sina.com.cn
22、Referer
浏览器向WEB 服务器表明自己是从哪个网页URL获得点击当前请求中的网址/URL,例如:Referer:http://www.jb51.net
23、User-Agent
浏览器表明自己的身份(是哪种浏览器)。例如:User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN;rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14
HTTP响应头
响应头向客户端提供一些额外信息,比如谁在发送响应、响应者的功能,甚至与响应相关的一些特殊指令。这些头部有助于客户端处理响应,并在将来发起更好的请求。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry- After、Server、Vary、Warning、WWW-Authenticate。对响应头域的扩展要求通讯双方都支持,如果存在不支持的响应头域,一般将会作为实体头域处理。
24、Age
当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时间了。
25、Server
WEB 服务器表明自己是什么软件及版本等信息。例如:Server:Apache/2.0.61 (Unix)
26、Accept-Ranges
WEB服务器表明自己是否接受获取其某个实体的一部分(比如文件的一部分)的请求。bytes:表示接受,none:表示不接受。
27、Vary
WEB服务器用该头部的内容告诉 Cache 服务器,在什么条件下才能用本响应所返回的对象响应后续的请求。假如源WEB服务器在接到第一个请求消息时,其响应消息的头部为:Content-Encoding: gzip; Vary: Content-Encoding,那么Cache服务器会分析后续请求消息的头部,检查其Accept-Encoding,是否跟先前响应的Vary头部值一致,即是否使用相同的内容编码方法,这样就可以防止Cache服务器用自己Cache 里面压缩后的实体响应给不具备解压能力的浏览器。例如:Vary:Accept-Encoding。
HTTP实体头
实体头部提供了有关实体及其内容的大量信息,从有关对象类型的信息,到能够对资源使用的各种有效的请求方法。总之,实体头部可以告知接收者它在对什么进行处理。请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括信息性头部Allow、Location,内容头部Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type,缓存头部Etag、Expires、Last-Modified、extension-header。
28、Allow
服务器支持哪些请求方法(如GET、POST等)。
29、Location
表示客户应当到哪里去提取文档,用于将接收端定位到资源的位置(URL)上。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。
30、Content-Base
解析主体中的相对URL时使用的基础URL。
31、Content-Encoding
WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip
32、Content-Language
WEB 服务器告诉浏览器理解主体时最适宜使用的自然语言。
33、Content-Length
WEB服务器告诉浏览器自己响应的对象的长度或尺寸,例如:Content-Length: 26012
34、Content-Location
资源实际所处的位置。
35、Content-MD5
主体的MD5校验和。
36、Content-Range
实体头用于指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式: Content-Range:bytes-unitSPfirst-byte-pos-last-byte-pos/entity-legth。例如,传送头500个字节次字段的形式:Content-Range:bytes0- 499/1234如果一个http消息包含此节(例如,对范围请求的响应或对一系列范围的重叠请求),Content-Range表示传送的范围,Content-Length表示实际传送的字节数。
37、Content-Type
WEB 服务器告诉浏览器自己响应的对象的类型。例如:Content-Type:application/xml
38、Etag
就是一个对象(比如URL)的标志值,就一个对象而言,比如一个html文件,如果被修改了,其Etag也会别修改,所以,ETag的作用跟Last-Modified的作用差不多,主要供WEB服务器判断一个对象是否改变了。比如前一次请求某个html文件时,获得了其 ETag,当这次又请求这个文件时,浏览器就会把先前获得ETag值发送给WEB服务器,然后WEB服务器会把这个ETag跟该文件的当前ETag进行对比,然后就知道这个文件有没有改变了。
39、Expires
WEB服务器表明该实体将在什么时候过期,对于过期了的对象,只有在跟WEB服务器验证了其有效性后,才能用来响应客户请求。是 HTTP/1.0 的头部。例如:Expires:Sat, 23 May 2009 10:02:12 GMT
40、Last-Modified
WEB服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT
RESTful架构
目前最流行的一种互联网软件结构。它结构清晰,符合标准,易于理解,扩展方便。
REST,即Representational State Transfer的缩写,表现层状态话转换。
如果一个架构符合REST原则,则称为RESTful架构。
REST的名称表示层状态转化,表示层指资源的表现层
资源,就是网络上的一个实体,或者网络上的一个具体信息。可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实现。可以用一个URI指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
表示层,把资源具体呈现出来的形式,叫做它的表示层。
比如,文本可以用txt格式表现,也可以用HTML格式,XML格式,JSON格式表现,甚至可以采用二进制格式。图片可以用JPG格式表现,也可以用PNG格式表现。
URI只代表资源的尸体,不代表它的形式。
状态转化,互联网通信协议HTTP协议是一个无状态协议。所有的状态都保存在服务器端。因此如果客户端想要操作服务器,必须通过某种手段,让服务端发生状态转化(State Transfer)。而这种转化是建立在表现层之上的,就是 表现层状态转化。
客户端用到的手段,只能是HTTP协议。具体来说,HTTP协议里面,
四个表示操作方式的动词:GET、POST、PUT、DELETE。分别对应四种基本操作。
- GET用来获取资源
- POST用来新建资源
- PUT用来更新资源
- DELETE用来删除资源
总结以下RESTful架构
- 每一个URI表示一种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过四个HTTP动词,对服务器资源进行操作,实现表现层状态转化
误区
最常见的一种设计错误,就是URI包含动词。因为资源表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。
举例:某个URI是/post/show/1,其中show是动词,这个URI就设计错误了。正确的是:/post/1,然后用GET方法表示show
如果某些动作是HTTP动词表达不了的,就应该把动作做成一种资源。
比如网上汇款,错误的URI是
POST /accounts/1/transfer/500/to/2
正确的是
POST /transaction HTTP/1.1
Host: 127.0.0.1
from=1&to=2&amount=500.00
协议
API与用户通信协议,使用HTTPS协议
域名
API部署在专用域名下,使用二级域名:api.example.com
如果很简单,并且不会进一步扩展,可以考虑放在主域名下:example.org/api
路径
RESTful架构中,每一个网址代表一种资源,所以网址中不能有动词,只能有名词,而且名词往往与数据库中的表格名对应。数据库中的表是同种记录的集合,所以API中的名词也应该使用复数
举例,有一个API提供动物园信息,则路径应该设计下面这样
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
- https://api.example.com/v1/employees
HTTP动词
常用的HTTP动词有下面五个
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
- PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
- DELETE(DELETE):从服务器删除资源。
过滤信息
如果记录数据很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果
- ?limit=10:指定返回记录的数量
- ?offset=10:指定返回记录的开始位置。
- ?page=2&per_page=100:指定第几页,以及每页的记录数。
- ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
- ?animal_type_id=1:指定筛选条件
状态吗
服务器向用户返回的状态码和提示信息,常见的有以下一些
- 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
- 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
- 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
- 204 NO CONTENT - [DELETE]:用户删除数据成功。
- 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
- 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
- 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
- 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
- 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
- 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
- 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
- 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
错误处理
如果状态码是4xx,应该向用户返回出错信息。返回的信息将error作为键名,错误信息作为键值即可
error: "Invalid API key"
返回结果
针对不同操作,服务器向用户返回的结果应该符合以下规范
- GET /collection:返回资源对象的列表(数组)
- GET /collection/resource:返回单个资源对象
- POST /collection:返回新生成的资源对象
- PUT /collection/resource:返回完整的资源对象
- PATCH /collection/resource:返回完整的资源对象
- DELETE /collection/resource:返回一个空文档
服务器返回的数据格式,尽量使用JSON,避免使用XML
OAuth2.0
OAuth是一个关于授权的开放网络标准。
名词定义
需要了解几个专用名词,尤其是几张图
- Third-party application:第三方应用程序,又称客户端
- HTTP Service:HTTP服务提供商,简称服务提供商
- Resource Owner:资源所有者,又称用户
- User Agent:用户代理,指浏览器
- Authorization Server:认证服务器,即服务提供商专门用来处理认证的服务器
- Resource Server:资源服务器,即服务提供商存放用户生成的资源的服务器。与认证服务器,可以是同一台
OAuth的作用就是让客户端安全可控地获取用户的授权,与服务商提供商进行互动
OAuth的思路
在客户端与服务提供商之间,设置了一个授权层(authorization layer)。客户端不能直接登陆服务提供商,只能登陆授权层,以此将用户客户端区分开来。客户端 登陆授权层所用的令牌(token),与用户的密码不同。用户可以在登陆的时候,指定授权层令牌的权限范围和有效期。
客户端登陆授权层之后,服务提供商根据令牌的权限范围和有效期,向客户端开放用户存储的资料
运行流程
B是关键,即用户怎样才能给与客户端授权。有了这个授权之后,客户端就可以获取令牌,进而凭借令牌获取资源
客户端授权模式
客户端必须得到用户的授权,才能获得令牌。OAuth定义了四种授权方式
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
授权码模式
功能最完整、流程最严密的授权模式。特点就是通过客户端的后台服务器,与服务提供商的认证服务器进行互动
下面是这些步骤所需的参数
A步骤,客户端申请认证URI,包含以下参数
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id:表示客户端的ID,必选项
- redirect_uri:表示重定向URI,可选项
- scope:表示申请的权限范围,可选项
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
例子
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
C步骤,服务器回应客户端的URI
- code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
例子
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
D步骤,客户端向认证服务器申请令牌的HTTP请求,包含以下参数
- grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
- code:表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id:表示客户端ID,必选项。
例子
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
E步骤,认证服务器发送HTTP回复,包含以下参数
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
例子
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
从上面代码可以看到,相关参数使用JSON格式发送(Content-Type:application/json)。HTTP头信息中明确指定不得缓存
简化模式
不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了授权码这个步骤。
所有步骤在浏览器中完成,令牌对访问者可见,且客户端不需要认证
下面是上面这些步骤所需要的参数。
A步骤中,客户端发出的HTTP请求,包含以下参数:
- response_type:表示授权类型,此处的值固定为"token",必选项。
- client_id:表示客户端的ID,必选项。
- redirect_uri:表示重定向的URI,可选项。
- scope:表示权限范围,可选项。
- state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
下面是一个例子。
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
C步骤中,认证服务器回应客户端的URI,包含以下参数:
- access_token:表示访问令牌,必选项。
- token_type:表示令牌类型,该值大小写不敏感,必选项。
- expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
下面是一个例子。
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。
根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。
密码模式
用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。
B步骤中,客户端发出的HTTP请求,包含以下参数:
- grant_type:表示授权类型,此处的值固定为"password",必选项。
- username:表示用户名,必选项。
- password:表示用户的密码,必选项。
- scope:表示权限范围,可选项。
下面是一个例子。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
C步骤中,认证服务器向客户端发送访问令牌,下面是一个例子
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
整个过程中,客户端不得保存用户的密码
客户端模式
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
A步骤中,客户端发出的HTTP请求,包含以下参数:
- granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
- scope:表示权限范围,可选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
认证服务器必须以某种方式,验证客户端身份
B步骤中,认证服务器向客户端发送访问令牌
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "example_parameter":"example_value" }
更新令牌
如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌。
客户端发出更新令牌的HTTP请求,包含以下参数:
- granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。
- refresh_token:表示早前收到的更新令牌,必选项。
- scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。
例子
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
#
IIS与ASP.NET管道
不同IIS版本处理请求也不一样
IIS5
IIS 5.x 运行在进程InetInfo.exe中,进程寄宿一个World Wide Web Publishing Service(W3SVC)服务。
W3SVC主要负责HTTP请求的监听、激活管理工作进程、加载配置等。
当检测到HTTP请求,IIS根据扩展名判断请求是静态还是动态。
静态资源,IIS直接响应内容。
动态资源,根据扩展名从IIS的处理程序映射中找到ISAPI动态链接库(Dynamic Link Library,DLL)
ISAPI,是一套本地的Win32 API,是IIS和其他动态Web应用或平台之间的纽带。
ISAPI支持ISAPI扩展和ISAPI筛选,扩展处理HTTP请求的接口。筛选可以进行查看,修改,转发,拒绝。
当收到ASP.NET资源请求,ISAPI会创建ASP.NET工作进程aspnet.exe.
IIS进程与工作进程之间通过命名管道(Named Pipes)进行通信。
工作进程初始化时,CLR会加载以构建一个托管的环境。对于某个Web应用的初次请求,CLR会为其创建一个AppDomain应用程序域。
寄存在IIS5.x的所有Web应用都运行在同一个进程的不同AppDomain里面。
IIS6
IIS6针对IIS5有以下两点修改。
1. 将ISAPI动态链接库直接加载到工作进程中。
2. IIS6引用应用程序池的机制,可以为一个或多个Web应用创建一个应用程序池。以避免所有应用都在一个进程里
可以为一个或多个Web应用创建应用程序池,每个应用程序池对应一个独立的工作进程,运行在不同应用程序池中的Web引用基于进程级别的隔离机制。
IIS6创建了一个HTTP.SYS的监听器,以驱动程序的形式运行在Windows内核模式下,是TCP/IP网络子系统的一部分。
HTTP.SYS好处如下
持续监听:由于是网络驱动程序,始终处于运行状态,对用户的HTTP请求能够及时作出反应。
更好的稳定性:HTTP.SYS运行在操作系统内核模式下,并不执行任何用户代码,本身不会受到Web应用,工作进程,IIS进程的影响。
数据缓存:某个资源被频繁请求,HTTP.SYS会把响应的内容进行缓存。
W3SVC在IIS6中,从进程InetInfo.exe转移到SvcHost.exe中了。
当HTTP.SYS监听到HTTP请求,将其分发给W3SVC进行解析,获取目标应用,获得目标应用运行的程序池或工作进程。
工作进程初始化过程中,ISAPI动态库被加载,负责进行CLR的加载、应用程序域的创建和Web初始化等工作。
IIS7
引入了Windows进程激活服务(Windows Process Activation Service,WAS)分流W3SVC承载的部分功能。
W3SVC有三大功能
1.HTTP请求接受:接受HTTP.SYS监听到的HTTP请求
2.配置管理:从元数据库中加载配置信息对相关组件进行配置
3.进程管理:创建、回收、监控工作进程
其中后两个功能实现到WAS中了。提供了非HTTP协议的支持,通过监听适配器接口,抽象出针对不同协议的监听器。
对应3中监听器,他们以Windows服务的形式进行工作。
NetTcpPortSharing:为WCF提供TCP端口共享,即同一个监听端口被多个进程共享
NetTcpActivator:为WAS提供基于TCP的激活请求,包含TCP监听器和对应的监听适配器
NetPipeActivator:为WAS提供命名管道的激活请求
NetMsmqActivator:为WAS提供基于MSMQ的激活请求
不论是从W3SVC接受到的请求,还是监听器接受的请求,最终都会流转到WAS中。
IIS7分为两种模式,经典模式跟IIS6相同,集成模式是一种统一的处理管道。
将ASP.NET请求管道和IIS请求管道组合在一起。可以提供更好的性能,可以完成配置和管理的模块化。继承模式的映射都在web.config中进行处理。
ASP.NET集成
IIS与ASP.NET是两个相互独立的管道,各自具有自己的一套HTTP处理机制。两个管道通过ISAPI连通。
IIS是第一道屏障,进行必要的前期处理。IIS通过ISAPI将请求分发给ASP.NET管道。
ASP.NET在自身管道范围内完成对HTTP请求的处理,结束后再返回IIS。IIS在进行后期处理。
IIS运行在非托管的环境中,ASP.NET管道则是托管。托管环境指CLR搭建的环境,非托管环境指可以由Windows直接调用。
ASP.NET管道
HTTP.SYS接收到HTTP请求是对web应用的第一次访问,加载CLR后IIS会通过AppDomainFactory创建一个AppDomaiin。
ISApiRuntime被加载,会接管该HTTP请求。
创建一个IsapiWorkerRequest对象封装当前的HTTP请求,将此对象传递给CLR的HttpRuntime(当前应用程序的 ASP.NET 运行时服务)
此时,HTTP请求正式进入ASP.NET管道。HttpRuntime会根据对象创建HTTPContext( HTTP 请求的所有 HTTP 特定的信息)俗称 请求上下文
HttpContext创建后,HttpRuntime会利用HttpApplicationFacotry创建HttpApplication(ASP.NET 应用程序内所有应用程序对象公用的方法、属性和事件)
HttpApplication初始化过程中,ASP.NET会根据配置文件加载并初始化HttpModule(HTTP模块初始化和处置事件)
HttpApplication会在处理HTTP请求的不同阶段触发不同的事件,HttpModule通过注册事件, 将操作注入HTTP请求处理流程中。
HttpApplication
(定义对 ASP.NET 应用程序内所有应用程序对象公用的方法、属性和事件。 此类是用户在 Global.asax 文件中定义的应用程序的基类)
整个ASP.NET基础架构的核心,负责处理分发给它的HTTP请求。
第一个请求抵达后,会创建多个HttpApplication对象,存放于对象池中。
在HTTPAppliccation处理请求的不同阶段会触发不同的事件。
对于ASP.NET应用来说,HttpApplication派生于Global.asax文件,可以通过此文件,对请求处理行为进行制定。
Global.asax 采用方法名匹配,按照“Application_{事件名}”进行事件注册。
其中事件名内容,就是Application中包含的事件。例如:
protected void Application_BeginRequest(Object sender, EventArgs e) { Application["StartTime"] = System.DateTime.Now; }
其中会有几个是针对整个应用程序而言,而不是针对请求。
- Application_Init:在每一个HttpApplication实例初始化的时候执行
- Application_Disposed:在每一个HttpApplication实例被销毁之前执行
- Application_Error:所有没有处理的错误都会导致这个方法的执行
- Application_Start:在程序初始化的时候执行。在Web应用程序的生命周期里就执行一次,这里只能放一些公用的信息,比如HttpApplicationState
- Application_End:应用程序结束时,在最后一个HttpApplication销毁之后执行。对应Application_Start,在整个生命周期里面也是只执行一次
- Session_Start:会话开始时执行
- Session_End:会话结束或过期时执行
请求事件执行顺序如下:
- BeginRequest:作为执行的 HTTP 管道链中的第一个事件发生,当 ASP.NET 的请求做出响应
- AuthenticateRequest:当安全模块已建立的用户标识时出现
- PostAuthenticateRequest:当安全模块已建立的用户标识时出现
- AuthorizeRequest:安全模块已验证用户身份验证时发生
- PostAuthorizeRequest:当前请求的用户已被授权时发生
- ResolveRequestCache:当 ASP.NET 完成授权事件以便从缓存中,跳过的事件处理程序 (例如,一个页面或 XML Web 服务) 执行的请求提供服务的缓存模块时发生。
- PostResolveRequestCache:ASP.NET 将绕过当前事件处理程序的执行,并允许缓存模块以处理从缓存请求时发生
- PostMapRequestHandler:当 ASP.NET 已映射到相应的事件处理程序的当前请求时出现
- AcquireRequestState:当 ASP.NET 获取与当前的请求相关联的当前状态 (例如,会话状态)
- PostAcquireRequestState:获取与当前的请求相关联的请求状态 (例如,会话状态) 时发生
- PreRequestHandlerExecute:ASP.NET 开始执行事件处理程序 (例如,一个页面或 XML Web 服务) 之前发生
- PostRequestHandlerExecute:当 ASP.NET 事件处理程序 (例如,一个页面或 XML Web 服务) 完成执行时发生
- ReleaseRequestState:ASP.NET 完成执行所有请求事件处理程序后发生。 此事件会导致状态模块保存当前的状态数据
- PostReleaseRequestState:当 ASP.NET 已完成执行所有请求事件处理程序和存储数据的请求状态时发生
- UpdateRequestCache:当 ASP.NET 完成执行事件处理程序,以便让缓存模块存储将用于为从缓存中的后续请求提供服务的响应时发生
- PostUpdateRequestCache:当 ASP.NET 完成更新的缓存模块和存储用于为从缓存中的后续请求提供服务的响应时发生
- LogRequest:ASP.NET 执行当前请求的任何日志记录之前发生
- PostLogRequest:当 ASP.NET 已完成处理的事件处理程序时发生 LogRequest 事件
- EndRequest:作为执行的 HTTP 管道链中的最后一个事件发生,当 ASP.NET 的请求做出响应
IHttpModule
(提供模块初始化和处置事件以实现类)
当请求转入ASP.NET管道时,最终负责处理该请求的是HttpHandler对象。在此之前会先加载HttpModule对象。
ASP.NET提供的很多基础功能都是通过HttpModule实现的。例如
OutputCacheModule:输出缓存功能
SessionStateModule:无状态的HTTP协议上实现基于会话的状态保持
WindowsAuthenticationModule + FormsAuthenticationModule + PassportAuthenticatinonModule:实现了三种典型的身份认证
UrlAuthorizationModule _ FileAuthorizationModule:基于URI和ACL文件的授权
IHttpHandler
(定义 ASP.NET 以异步方式处理使用自定义 HTTP 处理程序的 HTTP Web 请求而实现的协定)
对不同资源类型的请求,ASP.NET会加载不同的Handler来处理,比如aspx与asmx对应的Handler是不同的。
HttpHandler 可以配置到Web.config中。例子为svc资源的配置。
"*.svc" verb="*" type="System.ServiceModel.Activation.HttpHander" validate="false" /> "true" targetFramework="4.6" /> "4.6" /> "Forms"> "~/Account/login.aspx" timeout="2000">