在TCP/IP的模型图中 , 读者可以看到 , HTTP协议位于最上层的应用层 , 它是互联网上应用最为广泛的一种网络协议 , 所有 www 文件都必须遵守这个协议 .
HTTP 是一种无状态协议 . 无状态是指客户端和服务端之间不需要建立持久的连接 , 客户端发起一个请求 , 服务器端返回响应 , 这个连接就会被关闭 , 在服务器端不会保留该请求的有关信息 .
HTTP的工作流程如下 :
1 . 地址解析
HTTP协议是通过标准URL来请求指定的服务器中指定服务的 . 一个标的 URL 如下 :
http://www.baidu.com:80/index.html?name=tom&age=18
下面来解析一下 URL , 看看这些组成都是做什么的 :
(1) http: 协议类型 . 这里指的是要发送的是什么协议,还可以是FTP等其他协议 . 而这里请求的是服务器中的网页,所以使用的是常见的HTTP协议 .
(2) www.baidu.com:主机名 . 通过主机名,可以准确定位到要访问的那台服务器 . 而在前面说的网络通信中,IP是可以唯一表示服务器地址的,但IP烦琐复杂,很难记忆,所以人们就想了个办法,通过熟悉的英文、数字等来表示一台服务器的地址,称为域名。这样就需要一个文件(作为一个数据仓库)把IP和域名一一对应起来 . 在很早的时候,我们确实是这么做的,不过随着IP越来越多,文件也变得越来越大,不堪负重 . 于是人们就想到了把这些一一对应的关系都放到一台统一的服务器上,这台服务器被称为DNS域名解析系统,它会把域名解析成对应的IP .
(3) 80:端口号 . 用户已经可以通过域名或者IP访问到一台服务器了,但是一台服务器里有那么多的服务和应用,怎样才能准确找到用户需要访问的那个服务或应用呢?在服务器中,每个服务和应用都会开启一个进程,都会有一个进程号(PID),如果对外提供服务,则还会有一个唯一的端口号,这让外部应用可以直接通过这个端口号访问到指定的服务和应用。端口号的范围是0~65 535,一些常用的服务和应用都有默认的端口号,一般不能轻易更改,比如Web服务器的80端口、远程连接SSH服务的22端口、数据库MySQL的3306端口等等。因为80端口是Web服务器的默认端口,所以在写HTTP请求的URL的时候,80端口一般是省略的 .
(4) index.html:请求的文件名 . 用户通过域名和端口号已经能访问到Web服务器了,接下来就可以通过文件名来访问指定的文件了 . Web服务器一般都做好了路由,不同的路由所提供的访问文件的形式可能不一样,但核心都是一样的 .
(5) ?name=tom&age=18:请求参数 . 即使同一个网页,可能针对不同的用户,服务器要返回给客户端的信息也是不一样的 . 而服务器就是通过URL中“?”后面携带的参数不同来响应不同的用户或者同一个用户的不同请求的 .
2 . 封装HTTP 请求
这一步把上面写的 URL 以及本机的一些信息封装成一个 HTTP 请求数据包
3 . 封装 TCP 包
第三步就是封装 TCP 包 , 建立 TCP 连接 , 也就是常说的"三次握手" . 由于HTTP位于最上层的应用层 , 所以HTTP在工作之前要由 TCP 和 IP 协议建立网络连接 , 这就是TCP/IP协议族 , 因此互联网又称为 TCP/IP 网络 .
这里就少TCP/IP协议的"三次握手" , 首先由客户端发送建立连接的请求 , 客户端发送一个 syn 包 , 等待服务端的响应 ; 服务端收到 syn 包之后 , 返回给客户端一个表示确认的 syn 包 和 ack 包 , 最后客户端收到之后向服务端发送 ACK 包 , 发送完之后开始建立连接 , 如下图所示
4 . 客户端发送请求命令
第四步就是在连接建立之后 , 客户端发送 HTTP 请求到服务端与请求相关的信息都会包含在请求头和请求体中发送给服务器端 .
5 . 服务器端响应
服务器端在收到请求之后 , 根据客户端的请求发送给客户端相应的信息 , 相关的响应信息都会放在响应头和响应体中 .
- 关闭连接
服务器端在发送完响应之后 , 就会关闭连接 , 如果过客户端的请求的头部信息中有 Connection-alive , 那么客户端在响应完这个请求之后不会关闭连接 , 知道客户端的所有请求都响应完毕 , 才会关闭连接 , 这样大大节省了带宽和 IO 资源 .
请求和响应
HTTP请求室友两部分组成 : HTTP消息头和 HTTP消息体 . 消息头告诉服务器该请求是做什么的 , 消息体高速服务器怎么做 , 比如访问一个网页 , 头部信息可以到浏览器中的调试中心看 , 而消息体需要用户单机鼠标右键查看源码 , 那些HTML代码就是服务器返回给客户端的消息体 .
- 请求行
请求的第一行是请求行 , 里面有请求方法 , URL , 协议版本等 , 比如上图中 , 请求的方法是 GET , 请求的URL是/ , 协议版本是HTTP/1.1 .
常见的请求方式有GET 和 POST , GET 方式主要用于请求网络资源 , POST 方式主要用于表单提交 , 由于GET方式的参数是在地址栏中的 , 所以总是可见的 , 不是很安全 , 而且长度也有限制 (2048个字符) , 而 POST 方式的参数是封装成实体之后发送给服务器的 , 是不可见的 , 相对比较安全 , 用户的敏感信息一般采用post 方式提交 . - 请求头
每个头域都由一个头域名 , 冒号和值域组成 , 下面介绍一些最常见的头域 :
(1) Connection : 表示是否需要持久连接 , 如果服务器看到它的值为 keep-alive , 或者请求协议使用的是HTTP/1.1(默认使用持久连接) , 同一个页面如果包含多个资源 , 则只会使用一个连接 , 如Connection : keep-alive . 如果设置了 Connetion:close , 则每一个请求结束都会关闭连接 , 新的请求又会重新建立连接 , 一个网页至少有几十个资源请求 , 这样会浪费带宽和时间 .
(2) Host : 这个是必需的 , 表示请求的服务器地址是什么 , 是从URL 中提取出来的 . 比如 http://www.baidu.com/ 的host 就是 www.baidu.com , 这里是80端口 , 默认省略 ; 如果是其他端口 , 比如 http://www.baidu.com:8080 , 则Host是 www.baidu.com:8080 .
(3) Accept : 浏览器可以接受的媒体类型(MIME) , 如 Accept:text/html 代表可以接受HTML文档 , " * "代表接受任何类型 , 如 Accept:/ .
(4) Accept-Encoding : 浏览器申明自己接受的编码方法 , 通常指定压缩方法 , 是否支持压缩 , 支持什么格式的压缩 . - 请求正文
也叫请求数据 , 在使用post请求表单数据的时候 , 这些表单数据就会被放在 HTTP 请求的请求正文中 , 以加密的形式向服务器传输 .