HTTP 是一个拓展性非常好的协议。它依赖于资源或统一资源定位符(URI)的概念、一个简单的消息结构和一个客户端——服务器结构的通信流。在这些基础概念之上,近年来已经出现了许多拓展,以增加新的 HTTP 方法或首部的方式为 HTTP 协议增加了新的功能和语义。
话不多说,直接上图
一.HTTP 报文
HTTP/1.1 以及更早的 HTTP 协议报文都是语义可读的。在 HTTP/2 中,这些报文被嵌入到了一个新的二进制结构,帧。帧允许实现很多优化,比如报文标头的压缩以及多路复用。即使只有原始 HTTP 报文的一部分以 HTTP/2 发送出来,每条报文的语义依旧不变,客户端会重组原始 HTTP/1.1 请求。因此用 HTTP/1.1 格式来理解 HTTP/2 报文仍旧有效。
有两种 HTTP 报文的类型,请求与响应,每种都有其特定的格式。
请求(request)
请求由以下元素组成
-
一个 HTTP 方法,通常是由一个动词,像
GET
、POST
等,或者一个名词,像OPTIONS
、HEAD
等,来定义客户端执行的动作。典型场景有:客户端意图抓取某个资源(使用GET
);发送 HTML 表单的参数值(使用POST
);以及其他情况下需要的那些其他操作。 -
要获取的那个资源的路径——去除了当前上下文中显而易见的信息之后的 URL,比如说,它不包括协议(
http://
)、域名(这里的域名是developer.mozilla.org
),或是 TCP 的端口(这里的端口是80
)。 -
HTTP 协议版本号。
-
为服务端表达其他信息的可选标头。
-
请求体(body),类似于响应中的请求体,一些像 POST 这样的方法,请求体内包含需要了发送的资源。
响应(response)
响应报文包括了一下元素
-
HTTP 协议版本号。
-
一个状态码(status code),来指明对应请求已成功执行或是没有,以及相应的原因。
-
一个状态信息,这个信息是一个不权威、简短的状态码描述
-
HTTP 标头,与请求标头类似。
-
可选项,一个包含了被获取资源的主体。
二.基于http的api
XMLHttpRequest
是基于 HTTP 的最常用 API,可用于在用户代理和服务端之间交换数据。现代 Fetch API
提供相同的功能,并具有更强大和灵活的功能集。
另一种 API,server-sent 事件,是一种单向服务,允许服务端借助作为 HTTP 传输机制向客户端发送事件。使用 EventSource
接口,客户端可打开连接并创建事件处理器。客户端浏览器自动将 HTTP 流里到达的消息转换为适当的 Event
对象。继而将已知类型的事件,传递给先前注册过的事件处理器,其他未指明类型的事件则传递给 onmessage
事件处理器。
也就是说服务端没有收到客户端的请求,也可以向客服端发送消息(当然这不是websocket),是server-sent
三.Server-sent events
开发一个使用服务器发送事件的 Web 应用程序是很容易的。你只需要在服务器上编写一些代码将事件流传输到前端,而客户端的代码在处理传入事件部分几乎与 websocket 相同。这是一个单向的连接,所以你不能从客户端发送事件到服务器。
创建一个 EventSource 实例
使用生成事件的脚本 URL 创建一个 EventSource
对象,用来开启与服务器的连接并从中接收事件。
const evtSource = new EventSource("ssedemo.php");
如果生成事件的脚本不同源,应该创建一个新的包含 URL 和 options 参数的 EventSource
对象。例如,假设客户端脚本在 example.com
上:
const evtSource = new EventSource("//api.example.com/ssedemo.php", {
withCredentials: true
});
监听 message 事件
如果服务器发送的消息中没有 event
字段,则这些消息会被视为 message
事件。为了接收这些 message 事件,需要为 message
事件附加一个事件处理程序。
evtSource.onmessage = function(event) {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
newElement.innerHTML = "message: " + event.data;
eventList.appendChild(newElement);
}
监听自定义事件
如果服务器发送的消息中定义了 event
字段,就会以 event
中给定的名称作为事件接收。例如:
evtSource.addEventListener("ping", (event) => {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
const time = JSON.parse(event.data).time;
newElement.textContent = `ping at ${time}`;
eventList.appendChild(newElement);
});
最后补充一句,领导讲话喜欢讲三点,今天我们就了解三点,够用~