浅析http协议

服务器是什么

服务器在不同的语境下可能表达了不同的含义:

  • 一台独立的计算机
  • 一个应用程序

绝大部分使用,作为开发者,通常把服务器看作是一个应用程序
无论它是哪个概念,它都至少具有下面的特点:

  • 能够通过网络,被其他程序访问
  • 能够提供一些服务

如果一个服务器(应用程序),它仅仅为一个浏览器访问网站服务,我们称它为web服务器

实际上,目前的web服务器和游戏服务器界限已经非常模糊,可以认为,凡是在互联网中提供服务的服务器都是web服务器

通常,我们把访问服务器的程序,称之为客户端

实际上,web服务器不仅限于为浏览器提供服务,还可以为手机app、小程序、小游戏等常见互联网应用提供服务
本节课只考虑浏览器

常见的web服务器有:nginx、apache、iis

在开发阶段,web服务器往往安装在本地计算机,通常也称之为本地服务器

vscode有一个live server插件,其实它就是一个轻量级的web服务器

如何访问服务器

服务器程序可能在本机,也可能在远程,它一定运行在某一台计算机上

要在茫茫互联网中访问到服务器程序,就必须:

  • 精确的定位到服务器所在的计算机(host 主机名)
  • 精确定位到计算机中的服务器程序(端口号)
  • 精确定位到程序中的某个功能(path 定位服务)
    通常,我们使用url地址来描述以上3个信息

url地址全称为Uniform Resource Locator,统一资源定位符,是一个字符串,它的格式如下:

protocol://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就是/

  • query: 一种特殊格式的字符串,该字符串会交给web服务器处理,主要用于向服务器某个服务传递一些信息
    格式为:属性名=属性值&属性名=属性值

  • hash:一个普通的字符串,在浏览器的地址栏中,如果url其他位置的信息保持不变,仅变动hash,浏览器不会重新访问服务器,因此通常用于不刷新的页面内跳转(与id一起使用)

可以看出:

  • hostname是用于精准定位计算机的
  • port是用于精准定位服务器的
  • protocal是用于告诉服务器使用哪种协议进行传输数据
  • path是用于精准定位服务器上的服务的
  • query是在使用服务的时候传递的额外信息,具体看服务器要求
  • hash是一些额外信息,服务器要不要用具体看服务器要求

https://baike.baidu.com/item/HTML?a=1#1

  • protocal(协议名):https
  • port(端口号):443
  • hostname(ip/域名):baike.baidu.com
  • path(路径):item/HTML
  • query(参数):a=1
  • hash(哈希):1

注意:url仅支持ASCII字符,如果是包含非ASCII字符,会被现代浏览器自动进行编码

例如:

https://www.baidu.com/s?wd=王思聪

会被编码为

https://www.baidu.com/s?wd=%E7%8E%8B%E6%80%9D%E8%81%AA
url地址不能过长,因为很多浏览器对url地址长度是有限制的,chrome对url的长度限制为8182个ASCII字符

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

可以看出,该字符串有两个部分组成

请求行:请求方法 path 协议

  • 请求方法:一个普通的字符串,会被服务器读取到。常见的请求方法:GET、POST
  • path:即url中的 path + query + hash,服务器可能会用到path中的信息
  • 协议:协议以及版本号,目前固定为 HTTP/1.1

键值对:大量的属性名和属性值组合,可以自定义。

  • 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的query或hash中读取
  2. 如果是POST请求,读取请求体,业务数据从请求体中获取,关于请求体的格式,不同的服务器、同一个服务器的不同服务要求不同

在浏览器地址栏中输入url地址是不能产生POST请求的,可以使用表单提交产生POST请求

由于服务器对GET和POST处理的差异,造成了GET和POST请求的差异:

  • GET请求一般没有请求体,POST请求有
  • GET请求的业务数据放在地址中,安全性较差(误分享、被偷窥)
  • GET请求传递的业务数据量是有限的,POST是无限的(除非服务器限制)
  • GET请求利于分享页面结果,POST不行
  • 在浏览器中刷新或回退页面时,会按照该页面之前的请求方式重新发送请求,如果是GET请求,浏览器会重新发送GET请求;如果是POST请求,浏览器会重新构建之前的消息体数据,通常会弹出提示

响应消息格式

和请求类似,响应消息也分为响应头(response headers)和响应体(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

可以看出,该字符串有两个部分组成

  1. 响应行:协议 状态码 状态文本
    1. 协议:协议以及版本号,目前固定为 HTTP/1.1
    2. 状态码和状态文本:一个数字和数字对应的单词,来描述服务器的响应状态,浏览器会根据该状态码做不同的处理。
      1. 200 OK:一切正常。你好,我好,大家好。
      2. 301 Moved Permanently:资源已被永久重定向。你的请求我收到了,但是呢,你要的东西不在这个地址了,我已经永远的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了
      3. 302 Found:资源已被临时重定向。你的请求我收到了,但是呢,你要的东西不在这个地址了,我临时的把它移动到了一个新的地址,麻烦你取请求新的地址,地址我放到了请求头的Location中了
      4. 304 Not Modified:文档内容未被修改。你的请求我收到了,你要的东西跟之前是一样的,没有任何的变化,所以我就不给你结果了,你自己就用以前的吧。啥?你没有缓存以前的内容,关我啥事
      5. 400 Bad Request:语义有误,当前请求无法被服务器理解。你给我发的是个啥啊,我听都听不懂
      6. 403 Forbidden:服务器拒绝执行。你的请求我已收到,但是我就是不给你东西
      7. 404 Not Found:资源不存在。你的请求我收到了,但我没有你要的东西
      8. 500 Internal Server Error:服务器内部错误。你的请求我已收到,但这道题我不会,解不出来,先睡了
      9. 通常认为,0~399之间的状态码都是正常的,其他是不正常的
  2. 键值对:大量的属性名和属性值组合,可以在服务器响应的时候自定义。
    1. Content-Type:响应体中的数据格式,常见格式如下
      1. text/plain: 普通的纯文本,浏览器通常会将响应体原封不动的显示到页面上
      2. text/html:html文档,浏览器通常会将响应体作为页面进行渲染
      3. text/javascript:js代码,浏览器通常会使用JS执行引擎将它解析执行
      4. text/css:css代码,浏览器会将它视为样式
      5. image/jpeg:浏览器会将它视为jpg图片
      6. attachment:附件,浏览器看到这个类型,通常会触发下载功能
      7. 其他MIME类型
    2. Server:web服务器类型

响应体

响应消息的正文

在浏览器地址栏中输入一个页面地址,按下回车键后发生了什么?

  1. 浏览器将url地址补充完整:没有书写协议,添加上协议(DNS解析域名)
  2. 浏览器对url地址进行url编码:如果url地址中出现非ASCII字符,则浏览器会对其进行编码
  3. 浏览器构造一个没有消息体的GET请求,发送至服务器,等待服务器的响应,此时浏览器标签页往往会出现一个等待的图标
  4. 服务器接收到请求,将一个HTML页面代码组装到消息体中,响应给浏览器
  5. 浏览器拿到服务器的响应后,丢弃掉当前页面,开始渲染消息体的html代码。浏览器之所以直到这是一个html代码,是因为服务器的响应头指定了消息类型为text/html
  6. 浏览器在渲染页面的过程中,发现有其他的嵌入资源,如CSS、JS、图片等
  7. 浏览器使用不阻塞渲染的方式,重新向服务器发送对该资源的请求,拿到响应结果后根据Content-Type做相应处理
  8. 当所有的资源都已下载并处理后,浏览器触发window.onload事件

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("请求体内容"); //构建请求体,发送到服务器
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值