本篇内容会讲到
- 什么是服务器?
- 如何访问服务器?
- http 协议
- 请求消息格式
- 请求头
- 请求体
- GET 和 POST
- 响应消息格式
- 响应头
- 响应体
- 在浏览器地址栏中输入一个页面地址,按下回车键后发生了什么?
- ajax
什么是服务器?
如果所有程序都是单机的,会导致什么后果呢?
1. 数据难以共享
2. 受计算机配置的影响,运算速度差异巨大
3. 个人计算机的安全性堪忧,可能会受到恶意程序的影响
有了服务器之后,这些都可以轻松解决
服务器在不同的语境下可能表达了不同的含义:
1. 一台独立的计算机
2. 一个应用程序
绝大部分使用,作为开发者,通常把服务器看作是一个应用程序。
无论它是哪一个状态,它都至少具有以下两个特点:
1. 能够通过网络,被其他程序访问
2. 能够提供一些服务

如果一个服务器(应用程序),它仅仅为一个浏览器网站服务,我们称它为web 服务器
实际上,目前的web 服务器和游戏服务器界限已经非常模糊,可以认为,凡是在互联网中提供服务的服务器都是web 服务器

通常,我们把访问服务器的程序,称之为客户端
实际上, web 服务器不仅限于为浏览器提供服务,还可以为手机App、小程序、小游戏等常见互联网应用提供服务
本章内容只考虑浏览器
常见的 web 服务器有: nginx、 apache、iis
在开发阶段,web 服务器往往安装在本地计算机中,通常也称之为本地服务器
vscode 有一个 live server 插件,其实它就是一个轻量级的 web 服务器
如何访问服务器
服务器程序可能在本机,也可能在远程,它一定运行在某一台计算机上
要在茫茫互联网中访问到服务器程序,就必须:
1. 精确地定位到服务器所在的计算机
2. 精确地定位到计算机中的服务器程序
3. 精确地定位到程序中的某个功能
通常,我们使用 url 地址来描述以上3个信息
url 地址全称为 Uniform Resource Locator,统一资源定位符,是一个字符串,它的格式如下:
protocal://hostname:port/path?query#hash
- protocal: 使用的协议,选择不同的协议,会导致和服务器之间消息交互格式、连接方式的不同,大部分服务器都支持 http 和 https 两种协议。如果选择了服务器不支持的协议,会导致访问失败。
- hostname: 主机名,可以是ip、域名
- Ip: 每台计算机在网络中的唯一编码,127.0.0.1 表示本机
- 域名: 网络中容易记忆的唯一单词,通过 DNS 服务器可以将域名解析成 IP,localhost 会被解析成 127.0.0.1
- port: 端口号,0~65535之间的数字,相当于服务器计算机上的房号 ,使用的不同的端口号相当于敲不同房间的门。计算机上的程序可以监听一个或多个端口号,如果访问的端口号有程序被监听,则计算机会将到达的网络访问交给对应的程序来处理
- 端口号可以不写,使用默认值
- http 协议默认值80
- https 协议默认值443
- path: 一个普通的字符串,该字符串会交给web 服务器处理,主要用于定位服务
- 如果 path 为
/,则表示根路径,如http://www.baidu.com/的path 就是/
- 如果 path 为
- query:一种特殊格的字符串,该字符串会交给 web 服务器处理,主要用于向服务器某个服务传递一些信息
- 格式为:
属性名=属性值&属性名=属性值
- 格式为:
- hash: 一个普通的字符串,在浏览器的地址栏中,如果url 其它位置的信息保持不变,仅变动hash,浏览器不会重新访问服务器,因此通常用于不刷新的页面跳转
可以看出:
- hostname是用于精准定位计算机的
- port 是用于精准定位服务器的
- protocal 是用于告诉服务器使用哪种协议进行传输数据
- path 是用于精准定位服务器上的服务的
- query 是在使用服务的时候传递额外的信息的,具体看服务器要求
- hash 是一些额外信息,服务器要不要用具体看服务器要求
小练习,分析出下面url 地址的各部分内容
https://baike.baidu.com/item/HTML?a=1#1
注意:url 仅支持ASCII 字符,如果是包含非ASCII字符,会被现代浏览器自动进行编码
例如https://www.baidu.com/s?wd=王思聪
会被编码为https://www.baidu.com/swd=%E7%8E%8B%E6%80%9D%E8%81%AA
http 协议
我们可以通过url 地址访问服务器,但是,浏览器和服务器之间的数据到底是怎么交互的,数据的格式是什么,这取决于使用什么协议
最常见的协议,就是 http 协议
http 协议将和服务器的一次交互,看作是两段简单的过程组成:请求 request 和 响应 response
- 请求:客户端通过 url 地址发送数据到服务器的过程
- 响应:服务器收到请求数据后回馈数据给客户端的过程
-
当 请求-响应完成后,本次交互结束,如果需要得到额外的服务,则需要重新发送新的请求
同时,http 协议约定了请求的消息格式和响应的消息格式
请求的消息格式
请求消息格式有两部分组成:请求头 request headers 和 请求体 request body
请求头
请求头是一个多行文本的字符串
比如我们请求 http://www.baidu.com/s?wd=html, 得到的请求头可能如下:
GET /s?wd=html HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36
可以看出,该字符串有两个部分组成
1. 请求行:请求方法 path 协议
- 请求方法:一个普通的字符串,会被服务器读取到。常见的请求方法:GET、POST
- path:即url中的 path + search + hash,服务器可能会用到path中的信息
- 协议:协议以及版本号,目前固定为 HTTP/1.1
2. 键值对:大量的属性名和属性值组合,可以自定义
- Host:url地址中的hostname
- User-Agent:客户端信息描述
- 其他键值对
请求头描述了请求的元数据信息,这里的元数据信息是指与业务无关的额外信息
当我们在浏览器地址栏输入一个url按下回车后,浏览器会自动构建一个请求头,请求方法为GET,然后向服务器发送请求
请求体
包含业务数据的字符串
理论上,请求体可以是任意格式的字符串,但习惯上,服务器普遍能识别以下格式:
- application/x-www-form-urlencoded:
属性名=属性值&属性名=属性值... - application/json:
{"属性名":"属性值", "属性名":"属性值"} - multipart/form-data:使用某个随机字符串作为属性之间的分隔符,通常用于文件上传
由于请求体格式的多样性,服务器在分析请求体时可能无法知晓具体的格式,从而不知道如何解析请求体,因此,服务器往往要求在请求头中附带一个属性
Content-Type来描述请求体使用的格式
例如
Content-Type: application/x-www-form-urlencoded
Content-Type: application/json
Content-Type: multipart/form-data
GET 和 POST
虽然http协议并没有规定请求方法必须是什么,但随意的请求方法服务器可能无法识别
服务器一般都能识别GET和POST请求,并做出以下的差异化处理
1. 如果是GET请求,不读取请求体,业务数据从path的search或hash中读取
2.如果是POST请求,读取请求体,业务数据从请求体中获取,关于请求体的格式,不同的服务器、同一个服务器的不同服务要求不同
在浏览器地址栏中输入url地址是不能产生POST请求的,可以使用表单提交产生POST请求
由于服务器对GET和POST处理的差异,造成了GET和POST请求的差异:
1. GET 请求一般没有请求体,POST请求有
2. GET请求的业务数据放在地址中,安全性较差(误分享、被偷窥)
3. GET 请求传递的业务数据量是有限的,POST是无限的(除非服务器限制)
4. GET请求利于分享页面结果,POST不行
5. 在浏览器中刷新或回退页面时,会按照该页面之前的请求方式重新发送请求。如果是GET请求,浏览器会重新发送GET请求;如果是POST 请求,浏览器会重新构建之前的消息体数据,通常会弹出提示
响应消息格式
和请求类似,响应消息也分为响应头(response header) 和 响应体(response body)
响应头
比如我们请求 http://www.baidu.com/s?wd=html, 得到的响应头可能如下:
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Server: BWS/1.1
可以看出,该字符串有两个部分组成
- 响应行:协议 状态码 状态文本
- 协议:协议以及版本号,目前固定为 HTTP/1.1
- 状态码和状态文本:一个数字和数字对应的单词,来描述服务器的响应状态,浏览器会根据该状态码做不同的处理。
- 200 OK:一切正常。你好,
我好,大家好。 - 301 Moved Permanently:资源已被永久重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我已经永远的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了 - 302 Found:资源已被临时重定向。
你的请求我收到了,但是呢,你要的东西不在这个地址了,我临时的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了 - 304 Not Modified:文档内容未被修改。
你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事 - 400 Bad Request:语义有误,当前请求无法被服务器理解。
你给我发的是个啥啊,我听都听不懂 - 403 Forbidden:服务器拒绝执行。
你的请求我已收到,但是我就是不给你东西 - 404 Not Found:资源不存在。
你的请求我收到了,但我没有你要的东西 - 500 Internal Server Error:服务器内部错误。
你的请求我已收到,但这道题我不会,解不出来,先睡了 - 通常认为,0~399之间的状态码都是正常的,其他是不正常的
- 200 OK:一切正常。你好,
- 键值对:大量的属性名和属性值组合,可以在服务器响应的时候自定义。
- Content-Type:响应体中的数据格式,常见格式如下
- text/plain: 普通的纯文本,浏览器通常会将响应体原封不动的显示到页面上
- text/html:html文档,浏览器通常会将响应体作为页面进行渲染
- text/javascript:js代码,浏览器通常会使用JS执行引擎将它解析执行
- text/css:css代码,浏览器会将它视为样式
- image/jpeg:浏览器会将它视为jpg图片
- attachment:附件,浏览器看到这个类型,通常会触发下载功能
- 其他MIME类型
- Server:web服务器类型
- Content-Type:响应体中的数据格式,常见格式如下
响应体
响应消息的正文
在浏览器地址栏中输入一个页面地址,按下回车键后发生了什么?
- 浏览器将url地址补充完整:没有书写协议,添加上协议
- 浏览器对url地址进行url编码:如果url地址中出现非ASCII字符,则浏览器会对其进行编码
- 浏览器构造一个没有消息体的GET请求,发送至服务器,等待服务器的响应,此时浏览器标签页往往会出现一个等待的图标
- 服务器接收到请求,将一个HTML页面代码组装到消息体中,响应给浏览器
- 浏览器拿到服务器的响应后,丢弃掉当前页面,开始渲染消息体的html代码。浏览器之所以直到这是一个html代码,是因为服务器的响应头指定了消息类型为text/html
- 浏览器在渲染页面的过程中,发现有其他的嵌入资源,如CSS、JS、图片等
- 浏览器使用不阻塞渲染的方式,重新向服务器发送对该资源的请求,拿到响应结果后根据Content-Type做相应处理
- 当所有的资源都已下载并处理后,浏览器触发window.onload事件
服务器:根据请求头和请求体,创建一个响应头和响应体,发送给客户端
question1: 向服务器请求发送 http://www.abc.com/1.js 得到的一定是一个JS文件吗?
answer: 不一定。/1.js 是 path, 是一个普通字符串而已。
question2: 如果服务器给你的一定是一个js的响应体,浏览器是否一定当作JS来执行?
answer: 不一定,按什么来执行,取决于Content-type
ajax
不仅仅是浏览器可以发出请求并获得响应,任何具有网络通信能力的程序均可以这样做。
过去,在浏览器中,只有浏览器本身有发送请求的能力,直到ajax的出现。
ajax是一种技术,让JS语言在浏览器环境中获得了新的API,通过该API,JS代码拥有了和服务器通信的能力
传统的ajax代码如下
var xhr = new XMLHttpRequest(); //创建发送请求的对象
xhr.onreadystatechange = function(){ //当请求状态发生改变时运行的函数
// xhr.readyState: 一个数字,用于判断请求到了哪个阶段
// 0: 刚刚创建好了请求对象,但还未配置请求(未调用open方法)
// 1: open方法已被调用
// 2: send方法已被调用
// 3: 正在接收服务器的响应消息体
// 4: 服务器响应的所有内容均已接收完毕
// xhr.responseText: 获取服务器响应的消息体文本
// xhr.getResponseHeader("Content-Type") 获取响应头Content-Type
}
xhr.setRequestHeader("Content-Type", "application/json"); //设置请求头
xhr.open("请求方法", "url地址"); //配置请求
xhr.send("请求体内容"); //构建请求体,发送到服务器
来源:CSDN
作者:我要学前端
链接:https://blog.csdn.net/lan128lan/article/details/103928446
