如今互联网的网络架构已经从传统的C/S架构转变为更加方便、快捷的B/S架构,B/S大大的简化了使用网络应用的难度。
B/S架构带来了一下两方面的好处。
当一个用户在浏览器输入www.shsxt.com这个url时,将会发生很多操作,首先它会请求DNS把这个域名解析成对应的IP地址,然后根据这个IP地址找到对应的服务器。向这个服务器发送一个get请求,由这个服务器决定返回的数据资源给浏览器。在服务器端实际上还有很复杂的业务逻辑:服务器可能有很多台,到底指定哪台服务器来处理请求,这需要一个负载均衡设备来平均分配请求;还有请求的数据是存储在分布式缓存里还是一个静态文件中,或者是在数据库里;当数据返回时,浏览器解析数据发现还有一些静态资源(如CSS,JS或图片)时,又会发起另外的HTTP请求。
不管网络架构如何变化,始终有一些固定不变的原则需要遵守。
如何发起一个HTTP请求和如何建立一个Socket连接区别不大,只不过outputStream. write写的二进制字节数据格式要符合HTTP协议。浏览器在建立Socket连接之前,必须根据地址栏里输入的URL的域名DNS解析出IP地址,再根据这个IP地址和默认80端口与远程服务器建立Socket连接,然后浏览器根据这个URL组装成一个get类型的HTTP请求头,通过outputStream.write发送到目标服务器,服务器等待inputStream.read返回数据,最后断开这个连接。
当然,不同浏览器在如何使用这个已经建立好的连接,以及根据什么规则来管理连接,有各种不同的实现方法。一句话,发起一个HTTP请求的过程就是建立一个Socket通信的过程。
get
post
1、请求行
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行
请求方法(所有方法全为大写)有多种,各个方法的解释如下:
应用举例:
GET方法:在浏览器的地址栏中输入网址的方式访问网页时,浏览器采用GET方法向服务器获取资源,eg:GET /form.html HTTP/1.1 (CRLF)
POST方法:要求被请求服务器接受附在请求后面的数据,常用于提交表单。
POST /reg.jsp HTTP/ (CRLF)
Accept:image/gif,image/x-xbit,... (CRLF)
...
HOST:www.guet.edu.cn (CRLF)
Content-Length:22 (CRLF)
Connection:Keep-Alive (CRLF)
Cache-Control:no-cache (CRLF)
(CRLF) //该CRLF表示消息报头已经结束,在此之前为消息报头
user=jeffrey&pwd=1234 //此行以下为提交的数据
2、请求头

3、请求体
HTTP协议之响应 在接收和解释请求消息后,服务器返回一个HTTP响应消息。
HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文
1、状态行
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
2、响应头

3、响应正文
响应正文即服务器返回的资源内容
常见响应码
1、浏览器会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有www.shsxt.com对应的条目,而且没有过期,如果有且没有过期则解析到此结束。
注:我们怎么查看Chrome自身的缓存?可以使用 chrome://net-internals/#dns 来进行查看。
2、如果浏览器自身的缓存里面没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索解析到此结束.
注:怎么查看操作系统自身的DNS缓存,以Windows系统为例,可以在命令行下使用 ipconfig /displaydns 来进行查看。
3、 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果有则解析成功。
4、 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址)。
1) Client首先发送一个连接试探,这时候Client进入syn_sent状态,表示客户端等待服务器的回复。
2) Server监听到连接请求报文后,如同意建立连接,则向Client发送确认。这时服务器进入syn_rcvd,表示服务器已经收到Client的连接请求,等待client的确认。
3) Client收到确认后还需再次发送确认,同时携带要发送给Server的数据。一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。
GET命令的格式为: GET 路径/文件名 HTTP/1.0
文件名指出所访问的文件,HTTP/1.0指出Web浏览器使用的HTTP版本。现在可以发送GET命令:GET /mydir/index.html HTTP/1.0,
为了告知浏览器,Web服务器首先传送一些HTTP头信息,然后传送具体内容(即HTTP体信息),HTTP头信息和HTTP体信息之间用一个空行分开。
常用的HTTP头信息有:
① HTTP 1.0 200 OK 这是Web服务器应答的第一行,列出服务器正在运行的HTTP版本号和应答代码。代码"200 OK"表示请求完成。
② MIME_Version:1.0 它指示MIME类型的版本。
③ content_type:类型 这个头信息非常重要,它指示HTTP体信息的MIME类型。如:content_type:text/html指示传送的数据是HTML文档。
④ content_length:长度值 它指示HTTP体信息的长度(字节)。
浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。
B/S架构带来了一下两方面的好处。
- 客户端使用统一的浏览器(Browser)。由于浏览器具有统一性,她不需要特殊的配置和网络连接。浏览器的交互特性使得用户使用它非常简单,而且用户行为的可继性非常强。
- 服务端(Server)基于统一的HTTP。和传统的C/S架构使用的自定义的应用层协议不同,B/S使用的都是统一的HTTP。使用统一的HTTP也是为服务提供商简化了开发模式,大大的节省了开发成本。
一、B/S网络架构概述
B/S从前端到后端都得到了简化,都基于统一的应用层协议HTTP来交互数据。HTTP采用无状态的短连接的通信方式,通常情况下,一次请求就完成了一次数据交互,通常也对应一个业务逻辑,然后这次连接就断开了。当一个用户在浏览器输入www.shsxt.com这个url时,将会发生很多操作,首先它会请求DNS把这个域名解析成对应的IP地址,然后根据这个IP地址找到对应的服务器。向这个服务器发送一个get请求,由这个服务器决定返回的数据资源给浏览器。在服务器端实际上还有很复杂的业务逻辑:服务器可能有很多台,到底指定哪台服务器来处理请求,这需要一个负载均衡设备来平均分配请求;还有请求的数据是存储在分布式缓存里还是一个静态文件中,或者是在数据库里;当数据返回时,浏览器解析数据发现还有一些静态资源(如CSS,JS或图片)时,又会发起另外的HTTP请求。
不管网络架构如何变化,始终有一些固定不变的原则需要遵守。
- 所有的资源都要用一个URL来表示。URL是统一资源定位符,如果你要发布一个服务或者一个资源到互联网上,让别人能够访问到,那么你要有一个独一无二的URL。
- 必须基于HTTP与服务端交互。不管你访问的是国内还是国外的数据,是文本数据还是流媒体,都必须按照套路出牌,也就是都得采用统一的打招呼的方式,这样人家才能知道你要什么。
- 数据必须在浏览器中进行。当你获取到数据资源后,必须在浏览器上才能显示。
二、如何发起一个请求
如何发起一个HTTP请求?这个问题好像很简单,当你在浏览器里输入一个URL时,按回车键后这个HTTP请求就发起了,很快你就会看到这个请求的返回结果。但其实也很复杂,复杂的是能否不借助浏览器发起请求。如何发起一个HTTP请求和如何建立一个Socket连接区别不大,只不过outputStream. write写的二进制字节数据格式要符合HTTP协议。浏览器在建立Socket连接之前,必须根据地址栏里输入的URL的域名DNS解析出IP地址,再根据这个IP地址和默认80端口与远程服务器建立Socket连接,然后浏览器根据这个URL组装成一个get类型的HTTP请求头,通过outputStream.write发送到目标服务器,服务器等待inputStream.read返回数据,最后断开这个连接。
当然,不同浏览器在如何使用这个已经建立好的连接,以及根据什么规则来管理连接,有各种不同的实现方法。一句话,发起一个HTTP请求的过程就是建立一个Socket通信的过程。
三、HTTP协议解析
HTTP协议之请求 http请求由三部分组成,分别是:请求行、请求头、请求正文get
post
1、请求行
请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF
其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行
请求方法(所有方法全为大写)有多种,各个方法的解释如下:
| 方法 | 解释 |
| GET | 请求获取Request-URI所标识的资源 |
| POST | 在Request-URI所标识的资源后附加新的数据 |
| HEAD | 请求获取由Request-URI所标识的资源的响应消息报头 |
| PUT | 请求服务器存储一个资源,并用Request-URI作为其标识 |
| DELETE | 请求服务器删除Request-URI所标识的资源 |
| TRACE | 请求服务器回送收到的请求信息,主要用于测试或诊断 |
| CONNECT | 保留将来使用 |
| OPTIONS | 请求查询服务器的性能,或者查询与资源相关的选项和需求 |
应用举例:
GET方法:在浏览器的地址栏中输入网址的方式访问网页时,浏览器采用GET方法向服务器获取资源,eg:GET /form.html HTTP/1.1 (CRLF)
POST方法:要求被请求服务器接受附在请求后面的数据,常用于提交表单。
POST /reg.jsp HTTP/ (CRLF)
Accept:image/gif,image/x-xbit,... (CRLF)
...
HOST:www.guet.edu.cn (CRLF)
Content-Length:22 (CRLF)
Connection:Keep-Alive (CRLF)
Cache-Control:no-cache (CRLF)
(CRLF) //该CRLF表示消息报头已经结束,在此之前为消息报头
user=jeffrey&pwd=1234 //此行以下为提交的数据
2、请求头
3、请求体
HTTP协议之响应 在接收和解释请求消息后,服务器返回一个HTTP响应消息。
HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文
1、状态行
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
2、响应头
3、响应正文
响应正文即服务器返回的资源内容
常见响应码
四、HTTP请求到后端的过程
1. 域名解析
首先浏览器会解析www.shsxt.com 这个域名(准确的叫法应该是主机名)对应的IP地址。怎么解析到对应的IP地址?1、浏览器会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有www.shsxt.com对应的条目,而且没有过期,如果有且没有过期则解析到此结束。
注:我们怎么查看Chrome自身的缓存?可以使用 chrome://net-internals/#dns 来进行查看。
2、如果浏览器自身的缓存里面没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索解析到此结束.
注:怎么查看操作系统自身的DNS缓存,以Windows系统为例,可以在命令行下使用 ipconfig /displaydns 来进行查看。
3、 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件(位于C:\Windows\System32\drivers\etc),看看这里面有没有该域名对应的IP地址,如果有则解析成功。
4、 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过的是UDP协议向DNS的53端口发起请求,这个请求是递归的请求,也就是运营商的DNS服务器必须得提供给我们该域名的IP地址)。
2. 发起TCP的3次握手
拿到域名对应的IP地址之后,User-Agent(一般是指浏览器)会以一个随机端口(1024 < 端口 < 65535)向服务器的WEB程序(常用的有httpd,nginx等)80端口发起TCP的连接请求。这个连接请求(原始的http请求经过TCP/IP4层模型的层层封包)到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序(本文就以Nginx为例),最终建立了TCP/IP的连接。1) Client首先发送一个连接试探,这时候Client进入syn_sent状态,表示客户端等待服务器的回复。
2) Server监听到连接请求报文后,如同意建立连接,则向Client发送确认。这时服务器进入syn_rcvd,表示服务器已经收到Client的连接请求,等待client的确认。
3) Client收到确认后还需再次发送确认,同时携带要发送给Server的数据。一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。
3. 建立TCP连接后发起http请求
连接成功建立后,开始向web服务器发送请求,这个请求一般是GET或POST命令(POST用于FORM参数的传递)。GET命令的格式为: GET 路径/文件名 HTTP/1.0
文件名指出所访问的文件,HTTP/1.0指出Web浏览器使用的HTTP版本。现在可以发送GET命令:GET /mydir/index.html HTTP/1.0,
4. 服务器响应http请求,浏览器得到html代码
web服务器收到这个请求,进行处理。从它的文档空间中搜索子目录mydir的文件index.html。如果找到该文件,Web服务器把该文件内容传送给相应的Web浏览器。为了告知浏览器,Web服务器首先传送一些HTTP头信息,然后传送具体内容(即HTTP体信息),HTTP头信息和HTTP体信息之间用一个空行分开。
常用的HTTP头信息有:
① HTTP 1.0 200 OK 这是Web服务器应答的第一行,列出服务器正在运行的HTTP版本号和应答代码。代码"200 OK"表示请求完成。
② MIME_Version:1.0 它指示MIME类型的版本。
③ content_type:类型 这个头信息非常重要,它指示HTTP体信息的MIME类型。如:content_type:text/html指示传送的数据是HTML文档。
④ content_length:长度值 它指示HTTP体信息的长度(字节)。
5. 浏览器解析html代码,并请求html代码中的资源
浏览器拿到index.html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于每个资源大小不一样,而浏览器又多线程请求请求资源。浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。