#3.1 Web工作方式

我们平时浏览网页的时候,打开浏览器，输入网址，按下回车键，然后就出来了内容。在这个看似简单的行为背后，到底隐藏了些什么呢？

上面这个普通的浏览过程，底层其实是这样做的：浏览器是一个客户端，当你输入URL的时候，首先浏览器会去请求DNS服务器，通过DNS获取相应的域名对应的IP，然后通过IP和服务器建立socket连接，发送http请求信息，服务器接收到请求信息之后，处理相应的请求，返回http response信息，客户端接收到http信息之后开始渲染这些http response里面的content信息，断开和服务器的socket链接。

![](images/3.1.web2.png?raw=true)

 一个Web服务器也被称为HTTP服务器，它通过HTTP协议与客户端通信。这个客户端通常指的是Web浏览器(手机端客户端其实内部也是浏览器实现)。
    
Web服务器的工作原理简单的可以归纳为：

- 客户机通过socket建立到服务器的连接
- 客户端向服务器发送请求，http协议包,请求转化成服务器对应的文档
- 服务器向客户机发送应答，http协议包，请求的如果包含有动态语言的部分，那么动态语言把相应的数据结果返回给客户端
- 客户机与服务器断开。客户端解释HTML文档，在客户端屏幕上显示结果。

一个简单的事务处理事件就是这样实现的，看起来很复杂，做起来其实是挺简单的，需要注意的是客户机与服务器之间的通信是非连接的，也就是当服务器发送了应答后就与客户机断开连接，等待下一次请求。

##URL和DNS解析
我们浏览网页都是通过URL访问的，那么URL到底是怎么样的呢？

URL(Uniform Resource Locator)地址用于描述一个网络上的资源, 基本格式如下

	schema://host[:port#]/path/.../[?query-string][#anchor]
	scheme         指定低层使用的协议(例如：http, https, ftp)
	host           HTTP服务器的IP地址或者域名
	port#          HTTP服务器的默认端口是80，这种情况下端口号可以省略。如果使用了别的端口，必须指明，例如 http://www.cnblogs.com:8080/
	path           访问资源的路径
	query-string   发送给http服务器的数据
	anchor         锚

 DNS( Domain Name System)是“域名系统”的英文缩写，是一种组织成域层次结构的计算机和网络服务命名系统，它用于TCP/IP网络，它从事将主机名或域名转换为实际IP地址的工作。DNS就是这样的一位“翻译官”，它的基本工作原理可用下图来表示。

![](images/3.1.dns.png?raw=true)

DNS解析的过程如下，这个过程有助于我们理解DNS的工作模式

1、在浏览器中输入www.qq.com域名，操作系统会先检查自己本地的hosts文件是否有这个网址映射关系，如果有，就先调用这个IP地址映射，完成域名解析。 

2、如果hosts里没有这个域名的映射，则查找本地DNS解析器缓存，是否有这个网址映射关系，如果有，直接返回，完成域名解析。 

3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系，首先会找TCP/IP参数中设置的首选DNS服务器，在此我们叫它本地DNS服务器，此服务器收到查询时，如果要查询的域名，包含在本地配置区域资源中，则返回解析结果给客户机，完成域名解析，此解析具有权威性。
 
4、如果要查询的域名，不由本地DNS服务器区域解析，但该服务器已缓存了此网址映射关系，则调用这个IP地址映射，完成域名解析，此解析不具有权威性。

5、如果本地DNS服务器本地区域文件与缓存解析都失效，则根据本地DNS服务器的设置（是否设置转发器）进行查询，如果未用转发模式，本地DNS就把请求发至13台根DNS，根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理，并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后，将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后，如果自己无法解析，它就会找一个管理.com域的下一级DNS服务器地址(qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后，就会找qq.com域服务器，重复上面的动作，进行查询，直至找到www.qq.com主机。 

6、如果用的是转发模式，此DNS服务器就会把请求转发至上一级DNS服务器，由上一级服务器进行解析，上一级服务器如果不能解析，或找根DNS或把转请求转至上上级，以此循环。不管是本地DNS服务器用是是转发，还是根提示，最后都是把结果返回给本地DNS服务器，由此DNS服务器再返回给客户机。

![](images/3.1.dns2.png?raw=true)


通过上面的步骤，我们最后获取的是IP地址，也就是浏览器最后发起请求的时候是基于IP来和服务器做信息交互的。

##HTTP协议详解

HTTP协议是Web工作的核心，所以要了解清楚Web的工作方式就需要详细的了解清楚HTTP是怎么样工作的。

HTTP是一种让Web服务器与浏览器(客户端)通过Internet发送与接收数据的协议,它建立在TCP协议之上，一般采用TCP的80端口。它是一个请求、响应协议--客户端发出一个请求，服务器响应这个请求。在HTTP中，客户端总是通过建立一个连接与发送一个HTTP请求来发起一个事务。服务器不能主动去与客户端联系，也不能给客户端发出一个回调连接。客户端与服务器端都可以提前中断一个连接。例如，当浏览器下载一个文件时，你可以通过点击“停止”键来中断文件的下载，关闭与服务器的HTTP连接。

HTTP协议是无状态的，同一个客户端的这次请求和上次请求是没有对应关系，对HTTP服务器来说，它并不知道这两个请求来自同一个客户端。 为了解决这个问题， Web程序引入了Cookie机制来维护状态。

>HTTP协议是建立在TCP协议之上的，因此TCP攻击一样会影响HTTP的通讯，例如比较常见的一些攻击：SYN Flood是当前最流行的DoS（拒绝服务攻击）与DdoS（分布式拒绝服务攻击）的方式之一，这是一种利用TCP协议缺陷，发送大量伪造的TCP连接请求，从而使得被攻击方资源耗尽（CPU满负荷或内存不足）的攻击方式。

###HTTP请求信息(浏览器信息) 

我们先来看看Request消息的结构, Request 消息分为3部分，第一部分叫Request line, 第二部分叫Request header,第三部分是body。header和body之间有个空行，详细的如下所示

 - 请求行：GET/POST(流的组织(请求)方式) URL(地址+目录) 版本号
 - 请求头：
		
		Host:客户端IP和端口
        User-Agent:浏览器信息
        Accept：客户端能接收的数据类型
        Accept-encoding：是否支持压缩的流
        Accept-charset：客户端字符编码集
 - 空行：分割请求头和消息体
 - 消息体：请求的参数

我们通过fiddler抓包可以看到如下请求信息

![](images/3.1.http.png?raw=true)

![](images/3.1.httpPOST.png?raw=true)

我们可以看到GET请求消息体为空，POST请求带有消息体。

Http协议定义了很多与服务器交互的方法，最基本的有4种，分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源，而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查，改，增，删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息，而POST一般用于更新资源信息.
我们看看GET和POST的区别
1. GET提交的数据会放在URL之后，以?分割URL和传输数据，参数之间以&相连，如EditPosts.aspx?name=test1&id=123456.  POST方法是把提交的数据放在HTTP包的Body中.
2. GET提交的数据大小有限制（因为浏览器对URL的长度有限制），而POST方法提交的数据没有限制.
3. GET方式提交数据，会带来安全问题，比如一个登录页面，通过GET方式提交数据时，用户名和密码将出现在URL上，如果页面可以被缓存或者其他人可以访问这台机器，就可以从历史记录获得该用户的账号和密码。

###HTTP响应信息(服务器信息) 
我们再来看看HTTP的response信息，他的结构如下：

 - 状态行：HTTP版本  服务器状态(比如：404找不到...) 描述信息
 - 响应头

        Content-Type：服务器发送信息的类型
        Date：发送时间
        Server：服务器类型
 - 消息体：服务器发送给客户端的页面内容

Response 消息中的第一行叫做状态行，由HTTP协议版本号， 状态码， 状态消息 三部分组成。

状态码用来告诉HTTP客户端,HTTP服务器是否产生了预期的Response.

HTTP/1.1中定义了5类状态码， 状态码由三位数字组成，第一个数字定义了响应的类别

- 1XX  提示信息 - 表示请求已被成功接收，继续处理
- 2XX  成功 - 表示请求已被成功接收，理解，接受
- 3XX  重定向 - 要完成请求必须进行更进一步的处理
- 4XX  客户端错误 -  请求有语法错误或请求无法实现
- 5XX  服务器端错误 -   服务器未能实现合法的请求

我们看下面这个图展示了详细的返回信息，左边可以看到有很多的资源返回码，200是常用的，表示正常信息，302表示跳转。response header里面展示了详细的信息。

![](images/3.1.response.png?raw=true)


###HTTP协议是无状态的和Connection: keep-alive的区别
无状态是指协议对于事务处理没有记忆能力，服务器不知道客户端是什么状态。从另一方面讲，打开一个服务器上的网页和你之前打开这个服务器上的网页之间没有任何联系。

HTTP是一个无状态的面向连接的协议，无状态不代表HTTP不能保持TCP连接，更不能代表HTTP使用的是UDP协议（无连接）。

从HTTP/1.1起，默认都开启了Keep-Alive，保持连接特性，简单地说，当一个网页打开完成后，客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭，如果客户端再次访问这个服务器上的网页，会继续使用这一条已经建立的连接。

Keep-Alive不会永久保持连接，它有一个保持时间，可以在不同的服务器软件（如Apache）中设定这个时间

##请求实例

![](images/3.1.web.png?raw=true)

上面这张图我们可以了解到整个的通讯过程，同时细心的读者是否注意到了一点，一个URL请求但是左边栏里面为什么会有那么多的资源请求(这些都是静态文件，go对于静态文件有专门的处理方式)。

这个就是浏览器的功能，第一次请求url，服务器端返回的是html页面，然后浏览器开始渲染html，当解析到src里面的img资源、css资源、js资源，浏览器就会自动发起http请求，把需要的资源从服务器请求回来，然后浏览器就会宣布渲染出来，这样就是完整展现在我们面前的一个网页了。

>网页优化方面有一项是减少http请求次数，就是把尽量多的css和js合并在一起，尽量做到少的http请求。

## links
   * [目录](<preface.md>)
   * 上一节: [Web基础](<3.md>)
   * 下一节: [GO搭建一个web服务器](<3.2.md>)

## LastModified 
   * $Id$
