纸上得来终觉浅,绝知此事要躬行。
1. 网络基础
网络是所有连接、传输、服务的基础
1.1 OSI 和 TCP/IP 模型
1.2 IP 地址分类
所示均为
IPv4
的地址划分
分类
- A 类地址:
1-127
- B 类地址:
128-191
- C 类地址:
192-223
- D 类地址:
224-239
组播 - E 类地址:
240-254
私有地址
- A 类地址:
10.0.0.0/8
- B 类地址:
172.16.0.0/16 - 172.31.0.0/16
- C 类地址:
192.168.0.0/24 - 192.168.255.0/24
1.3 TCP 协议特性
TCP
提供一种面向连接的、可靠的字节流服务,在一个TCP
连接中,仅有两方进行彼此通信。TCP
不能用于广播和多播。
TCP
使用滑动窗口机制来实现流量控制TCP
通过动态改变窗口的大小进行拥塞控制
建立在三次握手连接的基础上
- 将数据打包成段
- 校验和使用
CRC-32
循环冗余加密算法来检验报文是否完整
- 校验和使用
- 确认、重传、超时
TCP
使用校验和、确认和重传机制来保证可靠传输
- 排序:
- 逻辑序号
- 流量控制
- 滑动窗口算法
- 拥塞控制
- 慢启动和拥塞避免算法
问题:快发/慢收导致接收方接收缓冲满了
- 解决:滑动窗口算法
- 滑动窗口是实现流控的基础
- 每次进行传输的时候,接收方每次接收数据之后告诉对方空闲窗口大小(空闲的内存大小),下一次发送方会根据对方反馈的信息进行数量上的发送。这样就能够避免问题的发生了,但是不知道接送双方之间的带宽有多大,有可能会压垮整个网络。
- 拥塞控制
- 拥塞控制算法防止发送者快发压垮带宽,压垮整个网络。拥塞控制使用慢启动和拥塞避免算法,发送方会检测网络中是否有拥塞(包丢失),从而减慢或者停止发送。
1.4 三次握手
服务器一定处于
Listen
状态,否则客户端发过来的连接会被拒绝。
握手过程
客户端发送第一次握手
- 客户端发送连接请求(
SYNC
包)到服务器 - 之后客户端由
Closed
状态转为Sync-Send
状态
- 客户端发送连接请求(
服务器收到客户端第一次握手
- 服务器收到客户端的请求(
SYNC
包),然后发送第二次握手(SYNC+ACK
包、即对客户端SYNC
包的确认)给客户端 - 之后服务器由
Listen
状态转为Sync-Recv
状态
- 服务器收到客户端的请求(
客户端收到服务器第二次握手
- 客户端收到服务器(
SYNC+ACK
包),然后发送第三次握手(ACK
包、即对服务器(SYNC+ACK
包)的确认)给给服务器 - 之后客户端就转为
ESTABLISHED
状态
- 客户端收到服务器(
服务器收到客户端第三次握手
- 服务器收到第三次握手的客户端(
ACK
包) - 之后服务器也进入了
ESTABLISHED
状态
- 服务器收到第三次握手的客户端(
注意
- 服务器和客户端的角色是相对的
1.5 四次挥手
服务器与客户端都处于
ESTABLISHED
状态,且有一方主动发起了关闭,另外一方会被动关闭。被动关闭的一方需要处理socket
的资源回收等,被动关闭的一方需要及时关闭,所以说被动关闭的一方出现大量CLOSE_WAIT
状态通常都是因为程序代码问题。
挥手过程 (假设客户端主动关闭连接)
客户端发送第一次挥手
- 客户端发送连接请求(
FIN+ACK
包)到服务器 - 之后由
ESTABLISHED
状态转为FIN_WAIT1
状态
- 客户端发送连接请求(
服务器收到客户端的第一次挥手
- 服务器收到客户端的第一次挥手(
FIN+ACK
包),然后发送第二次挥手(ACK
包,即对客户端FIN+ACK
包的确定)给服务器 - 之后,服务器进入
CLOSE_WAIT
状态,等待服务器自身的socket
关闭等处理(等待 IO,业务处理,资源回收等等)
- 服务器收到客户端的第一次挥手(
客户端收到服务器的第二次挥手
- 客户端收到服务器的第二次挥手
ACK
包 - 之后,客户端进入
FIN_WAIT2
状态,等待服务器关闭(服务器调用close
函数发送服务器的FIN
包)
- 客户端收到服务器的第二次挥手
服务器发送第三次挥手
- 服务器在处理完自己的事情,调用
close
函数发送服务器的FIN
包给客户端 - 之后,服务器进入
LAST_ACK
状态
- 服务器在处理完自己的事情,调用
客户端收到服务器第三次挥手
- 客户端收到服务器第三次挥手的
FIN
包,然后发送第四次挥手(第二个FIN+ACK
包,即对服务器FIN
包的确定) - 之后,客户端进入
TIME_WAIT
状态
- 客户端收到服务器第三次挥手的
服务器收到客户端第四次挥手
- 服务器收到客户端第二个
FIN+ACK
包 - 之后,服务器进入 CLOSED 状态
- 客户端等待
2MSL
时间,进入CLOSED
状态
- 服务器收到客户端第二个
状态转移
- 主动关闭的一方的状态迁移
FIN-WAIT1 -> FIN-WAIT2 -> TIME_WAIT-CLOSED
- 被动关闭的一方的状态迁移
CLOSE_WAIT -> LAST_ACK -> CLOSED
- 同时关闭,双方状态一致
FIN_WAIT1 -> CLOSING -> TIME_WAIT
注意
1.服务器和客户端的角色是相对的
2.FIN_WAIT2 状态等待时间是有限的,系统可配 tcp_fin_timeout 参数改变状态存活的时间
3.FIN_WAIT1 和 CLOSE_WAIT 是比较危险的状态,一般服务器网络故障首先要查看这俩个状态是否正常:CLOSE_WAIT 在上面说过,如果服务器代码有问题(忘记 close 等),服务器会一直有需要的 CLOSE_WAIT 状态的 socket,造成服务器不可连接;FIN_WAIT1 会在发出来 FIN 而没有手到 ACK 会重新发送 FIN,重发次数由系统参数配置:tcp_orphan_retries;如果系统负载过重,减少 tcp_orphan_retries 值可能有作用。
4.一般来说 FIN_WAIT1 几乎不可见,因为服务器之间的 ACK 速度非常快
1.6 握手/挥手状态
Client
端
Server
端
- TCP 的具体状态图
2. 套接字
Socket
是进程间通信(IPC
)的一种实现,允许位于不同主机甚至同一主机上不同进程之间进行通信。socket
本质上是对 TCP/IP
的封装,编程接口(API
)建立网络通信连接至少要一对端口号。
- 进程间通信的实现不是有
socket
,还有信号量、共享内存、消息队列等方式。- 套接字可以简单理解为:套接字 = IP 地址 + 端口号
2.1 分类
根据类型划分(根据传输使用的协议类型)
TCP
套接字(SOCK_STREAM
)- 流式通信协议,流式传输
- 建立虚链路、双向通信、可靠地传递、面向连接、无边界
UDP
套接字(SOCK_DGRAM
)- 数据报通信协议,数据报传输
- 不可靠地传递、有边界、无连接
- 裸套接字(
SOCK_RAW
)- 不使用传输层协议,直接和底层进行数据传输
根据域划分(根据其所使用的地址)
IPv4
协议簇(AF_INET
)- 不同主机之间进行通信时使用
IPv6
协议簇(AF_INET6
)- 不同主机之间进行通信时使用
UNIX
协议簇(AF_UNIX
)- 同一主机上不同进程之间通信时使用
- 不需要将数据向下传递,不占用
TCP
/UDP
协议栈,提升传输效率
我们经常在socket
编程中看到建立socket
时会使用上述类型
2.2 端口号
TCP/UDP
端口号的范围为0-65535
,各自独立不冲突。
端口分类
TCP
- 传输控制协议,面向连接的协议
- 通信前需要建立虚拟链路,结束后拆除链路
0-65535
UDP
- 用户数据报协议,无连接的协议
0-65535
IANA
组织
0-1023
- 众所周知的特权端口,永久的分配给固定的应用使用
22/tcp(ssh)
,80/tcp(http)
,443/tcp(https)
1024-41951
- 注册端口,但要求并不是特别严格,分配给程序注册为某应用使用
11211/tcp
,11211/udp (memcached)
,3306/tcp(mysql)
41952+
- 客户端程序随机使用的端口,动态端口或私有端口
- 其范围的定义:
/proc/sys/net/ipv4/ip_local_port_range
建立通信的套接字
- 服务使用一对套接字,服务端使用固定的套接字,
80/tcp(http)
,客户端使用41952+/65535
(动态端口)的随机一个端口,因为客户端是,随时都有可能关闭的。
2.3 系统调用
函数 | 说明 | 附加函数 |
---|---|---|
socket() |
向内核申请创建一个套接字 | 无 |
bind() |
进程和套接字绑定 | 无 |
listen() |
监听请求,没有请求时阻塞 | 无 |
accept() |
接收请求 | 无 |
connect() |
请求连接建立,客户端 | 无 |
read() |
读,从缓冲当中接收数据 | send() 、sendto() |
write() |
写,发送数据到套接字 | recv() 、recvfrom() |
3. HTTP 协议
超文本传输协议:是用于从万维网服务器传输超文本到本地浏览器的传送协议。
HTTP
是一个基于TCP/IP
通信协议来传递数据。HTTP
使用统一资源标识符(URI
)来传输数据和建立连接。默认工作在C/S
模式的80
端口上
3.1 三大特点
HTTP
是无连接
- 无连接的含义是限制每次连接只处理一个请求。
- 服务器处理完客户的请求,并收到客户的应答后,即断开连接。
- 采用这种方式可以节省传输时间。
HTTP
是媒体独立的
- 这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过
HTTP
发送。 - 客户端以及服务器指定使用适合的
MIME-type
内容类型。
HTTP
是无状态
HTTP
协议是无状态协议。- 无状态是指协议对于事务处理没有记忆能力。
- 缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
- 另一方面,在服务器不需要先前信息时它的应答就较快。
注释:多功能英特网邮件扩展(MIME
),最早用于SMTP
上的,使得我们可以基于文本协议发送非文本数据。当http
引入MIME
,TCP
也可以基于文本协议发送非文本数据,这也是支持多媒体的原因。其中MIME
类型的定义分为主类型/从类型(major/minor
)
3.2 协议版本
HTTP/0.9
- 原型版本且功能简陋,只实现了一个**
GET
**命令,且不支持请求头
HTTP/1.0
- 优点
- 第一个广泛使用的版本
- 增加请求与响应支持头域
- 支持**
MIME
类型**,响应对象不只限于超文本 - 支持许多动词方法:
GET
、HEAD
、POST
- 支持长连接(但默认还是使用短连接),多字符集支持,缓存
- 新增状态码(
status code
)、多部分发送(multi-part type
)、权限(authorization
)等
- 缺点
HTTP
的连接默认还是短连接,所以每次请求都需要三次握手/四次挥手的过程,非常消耗服务器性能。虽然可以使用非标准的Connection: keep-alive
字段来支持长连接,但是这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。
HTTP/1.1
- 优点
- 引入了持久连接,即
TCP
连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive
- 标准化**
Content-Length
**字段 - 增加分块传输编码传输模式
- 引入了管道机制,即在同一个
TCP
连接里面,客户端可以同时发送多个请求 - 新增了许多动词方法:
PUT
、PATCH
、HEAD
、OPTIONS
、DELETE
- 客户端请求的头信息新增了**
Host
**字段,用来指定服务器的域名
- 引入了持久连接,即
- 缺点
- 虽然
1.1
版允许复用TCP
连接,但是同一个TCP
连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为队头堵塞。 - 为了避免这个问题,只有两种方法:一是
减少请求数
,二是同时多开持久连接
。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS
代码、域名分片等等。如果HTTP
协议设计得更好一些,这些额外的工作是可以避免的。
- 虽然
spdy
- 2009 年,谷歌公开了自行研发的
SPDY
协议,主要解决HTTP/1.1
效率不高的问题 - 这个协议在
Chrome
浏览器上证明可行以后,就被当作HTTP/2
的基础,主要特性都在HTTP/2
之中得到继承
HTTP/2.0
- 二进制协议
HTTP/1.1
版的头信息肯定是文本(ASCII
编码),数据体可以是文本,也可以是二进制。HTTP/2
则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为帧(frame
):头信息帧和数据帧。- 二进制协议的一个好处是,可以定义额外的帧。
HTTP/2
定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。
- 多工
HTTP/2
复用TCP
连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了队头堵塞。- 举例来说,在一个
TCP
连接里面,服务器同时收到了A
请求和B
请求,于是先回应A
请求,结果发现处理过程非常耗时,于是就发送A
请求已经处理好的部分, 接着回应B
请求,完成后,再发送A
请求剩下的部分。 - 这样双向的、实时的通信,就叫做多工(
Multiplexing
)。
- 数据流
- 因为
HTTP/2
的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。 HTTP/2
将每个请求或回应的所有数据包,称为一个数据流(stream
)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID
,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID
一律为奇数,服务器发出的,ID
为偶数。- 数据流发送到一半的时候,客户端和服务器都可以发送信号(
RST_STREAM
帧),取消这个数据流。1.1
版取消数据流的唯一方法,就是关闭TCP
连接。这就是说,HTTP/2
可以取消某一次请求,同时保证TCP
连接还打开着,可以被其他请求使用。 - 客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
- 因为
- 头信息压缩
HTTP
协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie
和User Agent
,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2
对这一点做了优化,引入了头信息压缩机制(header compression
)。一方面,头信息使用gzip
或compress
压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。
- 服务器推送
HTTP/2
允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push
)。- 常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析
HTML
源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
注释
- 分块传输编码
- 使用
Content-Length
字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。 - 更好的处理方法是,产生一块数据,就发送一块,采用流模式(
stream
)取代缓存模式(buffer
)。因此,1.1
版规定可以不使用Content-Length
字段,而使用分块传输编码。只要请求或回应的头信息有Transfer-Encoding
字段,就表明回应将由数量未定的数据块组成(Transfer-Encoding: chunked
)。
- 使用
3.3 会话跟踪
会话:客户端打开与服务器的连接发出请求到服务器响应客户端请求的全过程称。
会话跟踪:指的是对同一个用户对服务器的连续的请求和接受响应的监视。
会话跟踪常用的方法:URL
重写、隐藏表单域、Cookie
、Session
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
也将失效。
注释:更新信息跨站攻击(SXRF/XSS)
3.4 完整的请求处理过程
- (1) 建立或处理连接
- 接收请求或拒绝请求
- (2) 接收请求
- 接收来自于网络的请求报文中对某资源的一次请求的过程
- (3) 处理请求
- 对请求报文进行解析,并获取请求的资源及请求方法等相关信息
- (4) 访问资源
- 获取请求报文中请求的资源
web
服务器负责向请求者提供对方请求的静态资源或动态运行后生成的资源,这些资源放置于本地文件系统某路径下,此路径通常称为DocRoot
。web
服务器资源路径映射方式:DocRoot
、Alias
、虚拟主机DocRoot
、用户家目录DocRoot
- (5) 构建响应报文
- 资源的
MIME
类型:显式分类、魔法分类、协商分类
- 资源的
- (6) 发送响应报文
- 响应客户端请求的资源内容
- (7) 记录日志
- 记录访问服务器的客户端信息
3.5 并发访问响应模型
单进程I/O
结构
- 启动一个进程处理用户请求,而且一次只处理一个,多个请求被串行响应
多进程I/O
结构
- 并行启动多个进程,每个进程响应一个请求
- 启动大量进程时,进程间切换很消耗
CPU
性能,而且很消耗内存
复用I/O
结构
- 一个进程响应
n
个请求,c10k
问题 - 事件驱动:
event-driven
基于事件回调 - 多线程模型:一个进程生成
n
个线程,每个线程响应一个用户请求
复用的多进程I/O
结构
- 启动多个(
m
)进程,每个进程响应n
个请求
注释:在Linux
上并非非常轻量,因为Linux
对待进程和线程几乎一样,所以线程并非那么轻量。
3.6 统一资源定位符
- 介绍
URL
(Unifrom Resource Locator
)是统一资源定位符
- 基本语法
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
- 分类
URL
方案:scheme
- 服务器地址:
ip:port
- 资源路径:
path
# 基本语法:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
# params: 传递参数
http://www.escapelife.com/bbs/hello;gender=f
# query:查询参数
http://www.escapelife.com/bbs/item.php?username=tom&title=abc
# frag:锚点
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html-single/Installation_Guide/index.html#ch-Boot-x86
3.7 method
方法
编号 | 请求方法 | 解释说明 |
---|---|---|
1 | GET |
从服务器获取一个资源 |
2 | HEAD |
只从服务器获取文档的响应首部 |
3 | POST |
向服务器发送要处理的数据 |
4 | PUT |
将请求的主体部分存储在服务器上 |
5 | DELETE |
请求删除服务器上指定的文档 |
6 | TRACE |
追踪请求到达服务器中间经过的代理服务器 |
7 | OPTIONS |
请求服务器返回对指定资源支持使用的请求方法 |
3.8 http 状态码
- 状态码分类
1xx:100-101, 信息提示;
2xx:200-206, 成功
3xx:300-305, 重定向
4xx:400-415, 错误类信息,客户端错误
5xx:500-505, 错误类信息,服务器端错误
- 常用的状态码
编号 | 状态码 | 解释说明 | 状态码说明 |
---|---|---|---|
1 | 200 |
成功,请求的所有数据通过响应报文的entity-body 部分发送 |
OK |
2 | 301 |
请求的 URL 指向的资源已经被删除;但在响应报文中通过首部Location 指明了资源现在所处的新位置 |
Moved Permanently |
3 | 302 |
与301 相似,但在响应报文中通过Location 指明资源现在所处临时新位置 |
Found |
4 | 304 |
客户端发出了条件式请求,但服务器上的资源未曾发生改变,则通过响应此响应状态码通知客户端 | Not Modified |
5 | 401 |
需要输入账号和密码认证方能访问资源 | Unauthorized |
6 | 403 |
请求被禁止 | Forbidden |
7 | 404 |
服务器无法找到客户端请求的资源 | Not Found |
8 | 500 |
服务器内部错误 | Internal Server Error |
9 | 502 |
代理服务器从后端服务器收到了一条伪响应 | Bad Gateway |
3.9 请求头信息
请求头信息就是浏览器请求中的
headers
部分
格式
Name: Value
首部的分类
- 通用首部
- 请求首部
- 响应首部
- 实体首部
- 扩展首部
通用首部
# 通用首部
Date: 报文的创建时间
Via:显示报文经过的中间节点
Connection:连接状态,表示是否需要持久连接
keep-alive:持久连接;http1.1版本为默认行为
close:关闭持久连接
Cache-Control:控制缓存
no-cache:不适用缓存
max-age:缓存的最大时长
Pragma:控制缓存;http1.1版本不再使用Cache-Control
Transfer-Encoding:传输数据是否分块(chunked)
chunked:支持分块传输
- 请求首部
# 请求首部
Accept:通过服务器自己可接受的媒体类型;
Accept-Charset:字符编码
Accept-Encoding:接受编码格式,如gzip
Accept-Language:接受的语言
Client-IP:
Host: 请求的服务器名称和端口号
Referer:包含当前正在请求的资源的上一级资源;
User-Agent:客户端代理
条件式请求首部:
Expect:
If-Modified-Since:自从指定的时间之后,请求的资源是否发生过修改;
If-Unmodified-Since:自从指定的时间之后,请求的资源是否没有发生过修改;
If-None-Match:本地缓存中存储的文档的ETag标签是否与服务器文档的Etag不匹配;
If-Match:是否匹配;
安全请求首部:
Authorization:向服务器发送认证信息,如账号和密码;
Cookie: 客户端向服务器发送cookie
Cookie2:
代理请求首部:
Proxy-Authorization: 向代理服务器认证
- 响应首部
# 响应首部
信息性:
Age:响应持续时长
Server:服务器程序软件名称和版本
协商首部:某资源有多种表示方法时使用
Accept-Ranges:服务器可接受的请求范围类型
Vary:服务器查看的其它首部列表;
安全响应首部:
Set-Cookie:向客户端设置cookie;
Set-Cookie2:
WWW-Authenticate:来自服务器的对客户端的质询认证表单
- 实体首部
# 实体首部
Allow: 列出对此实体可使用的请求方法
Location:告诉客户端真正的实体位于何处,重定向使用
Content-Encoding:内容编码格式
Content-Language:内容使用的语言
Content-Length: 主体的长度
Content-Location: 实体真正所处位置;
Content-Type:主体的对象类型
缓存相关:
ETag:实体的扩展标签;
Expires:实体的过期时间;
Last-Modified:最后一次修改的时间
# 请求头信息实例
Cache-Control:public, max-age=600
Connection:keep-alive
Content-Type:image/png
Date:Tue, 28 Apr 2015 01:43:54 GMT
ETag:"5af34e-ce6-504ea605b2e40"
Last-Modified:Wed, 08 Oct 2014 14:46:09 GMT
Accept:image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:access.redhat.com
If-Modified-Since:Wed, 08 Oct 2014 14:46:09 GMT
If-None-Match:"5af34e-ce6-504ea605b2e40"
Referer:https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html-single/Installation_Guide/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36