http协议之数据交互
2020-09-13 21:40:28 阿炯

HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中 POST 一般用来向服务端提交数据,这里主要讨论以 POST 方法向服务器提交数据的几种方式。

HTTP 协议是以 ASCII 码传输,建立在 TCP/IP 协议之上的应用层规范,规范把 HTTP 请求分为三个部分:状态行请求行、请求头、消息主体:
<method> <request-URL> <version>
<headers>
<entity-body>

协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求满足上面的格式就可以。

但数据发送出去后,还需要服务端解析成功才有意义。一般服务端语言如 php、perl 及其它们的框架,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到 POST 提交数据方案,包含了 Content-Type 和消息主体编码方式两部分。

Content-Type

Content-Type是指http/https发送信息至服务器时的内容编码类型,用于表明发送数据流的类型,服务器根据编码类型使用特定的解析方式,获取数据流中的数据。

在网络请求中,常用的Content-Type有如下:
text/html, text/plain, text/css, text/javascript, image/jpeg, image/png, image/gif, application/x-www-form-urlencoded, multipart/form-data, application/json, application/xml 等。

其中:text/html, text/plain, text/css, text/javascript, image/jpeg, image/png, image/gif 都是常见的页面资源类型。

常见的媒体格式类型如下:
text/html: HTML格式
text/plain:纯文本格式
text/xml: XML格式
image/gif:gif图片格式
image/jpeg:jpg图片格式
image/png:png图片格式

以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml: XML数据格式
application/atom+xml :Atom XML聚合格式
application/json: JSON数据格式
application/pdf:pdf格式
application/msword:Word文档格式
application/octet-stream: 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded:<form encType="">中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data:需要在表单中进行文件上传时,就需要使用该格式

application/x-www-form-urlencoded, multipart/form-data, application/json, application/xml 这四个是ajax的请求,表单提交或上传文件的常用的资源类型。

form表单中可以定义enctype属性,该属性的含义是在发送到服务器之前应该如何对表单数据进行编码,默认的情况下,表单数据会编码为"application/x-www-form-unlencoded"。

enctype常用的属性值如下:application/x-www-form-unlencoded:在发送前编码所有字符(默认情况下);而multipart/form-data不对字符编码,所有在文件上传时候,使用该值。

Content-Type的差异

传统的ajax请求时候,Content-Type默认为文本类型
传统的form提交的时候,Content-Type默认为Form类型
axios传递字符串的时候,Content-Type默认为Form类型
axios传递对象的时候,Content-Type默认为JSON类型

Content-Type的值,Form与非Form时,payload的区别:
都只支持字符串类型
Form需要传递的格式为key1=value1&key2=value2,类似GET请求的QueryString格式
非Form一般为JSON.stringify(formDataObject)形式

因此后端如果取不到值,无论何种形式传递,后端解析表单信息的时候,会考虑Content-Type。如果是JSON字符串的话,后端解析内容时候,肯定要去解析JSON。如果是key1=value1&key2=value2的形式,则需要去分割字符串。这些事情一般后端使用的框架会去处理,但是框架给后端提供取值接口有可能是不同的,所以在处理请求问题时,一定要跟后端商量好是用JSON还是FormData。

application/x-www-form-urlencoded


这应该是最常见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样:
POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_POST['title'] 可以获取到 title 的值,$_POST['sub'] 可以得到 sub 数组。

很多时候用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是'application/x-www-form-urlencoded;charset=utf-8'。

application/x-www-form-urlencoded 是最常用的一种请求编码方式,支持GET/POST等方法,所有数据变成键值对的形式 key1=value1&key2=value2 的形式,并且特殊字符需要转义成utf-8编号,如空格会变成'%20'。数据被编码成以 '&' 分隔的键值对,同时以 '=' 分隔键和值,非字母或数字的字符会被 percent-encoding,这也就是为什么这种类型不支持二进制数据(应使用 multipart/form-data 代替)。

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
  <script type="text/javascript" src="/js/jquery.js"></script>
</head>
<body>
  <div id="app">
    <div class="btn">发送post请求</div>
  </div>
  <script>
    var obj = {
      "name": 'CntFreeOA',
      "info": 'Front-End',
    };
    $('.btn').click(function() {
      $.ajax({
        url: 'www.example.com',
        type: 'POST',
        dataType: 'json',
        data: obj,
        success: function(d) {}
      })
    });
  </script>
</body>
</html>

如果请求类型type是GET的话,那么格式化的字符串将直接拼接在url后发送到服务端;如果请求类型是POST,那么格式化的字符串将放在http body的Form Data中发送。

multipart/form-data

这是一个常见的 POST 数据提交的方式。使用表单上传文件时,必须让 <form> 表单的 enctype 等于 multipart/form-data。它主要是将多条表单的数据处理为一条消息,发送到服务器。多条消息之间用分隔符分开,分隔符用 boundary=xxxxxx 来定义,xxxxx就是分隔符。

这样一个 HTTP 请求,由于有 boundary 隔离,既可以上传文本消息的同时,也可以上传文件。当上传的字段是文件时,可用 Content-Type 标明文件类型。来看一个请求示例:
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="firefox.png"
Content-Type: image/png

PNG ... content of firefox.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

You set request header Content-Type: multipart/form-data; boundary=HereGoes. Then this should be a valid request body:
--HereGoes
Content-Disposition: form-data; name="myJsonString"
Content-Type: application/json

{"foo": "bar"}
--HereGoes
Content-Disposition: form-data; name="photo"
Content-Type: image/jpeg
Content-Transfer-Encoding: base64

<...JPEG content in base64...>
--HereGoes--

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。使用表单上传文件时,必须指定表单的 enctype属性值为 multipart/form-data,请求体被分割成多部分,每部分使用'--boundary'分割。

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
</head>
<body>
  <div id="app">
    <form action="http://www.example.com" method="POST" enctype="multipart/form-data">
      <p>username: <input type="text" name="fname" /></p>
      <p>age: <input type="text" name="age" /></p>
      <input type="submit" value="提交" />
    </form>
  </div>
</body>
</html>

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

随着越来越多的 Web 站点,尤其是 WebApp,基本上使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利,此时JSON开始走向了我们。

application/json

application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上现在越来越多的应用把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。尤其需要提交的数据层次非常深,就将数据 JSON 序列化之后来提交的。json方式的优点是它可以传递结构复杂的数据形式,比如对象里面嵌套数组这样的形式等;直接json对象传递的话,对于后端应用的处理来说更简单。

<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
  <script type="text/javascript" src="/js/jquery.js"></script>
</head>
<body>
  <div id="app">
    <div class="btn">发送post请求</div>
  </div>
  <script>
    $('.btn').click(function(){
      $.ajax({
        url: 'http://www.example.com',
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify({a: [{b:1, a:1}],b: [1,2,3]}),
        success: function(d) {}
      })
    });
  </script>
</body>
</html>

Google 的 AngularJS 中的 Ajax 功能,默认就是提交 JSON 字符串。例如下面这段代码:
var data = {'title':'test', 'sub' : [1,2,3]};
$http.post(url, data).success(function(result) {
    ...
});

最终发送的请求是:
POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8
{"title":"test","sub":[1,2,3]}

这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包及开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。一些 php 框架已经开始这么做了。

当然 AngularJS 也可以配置为使用 x-www-form-urlencoded 方式提交数据。如有需要,可以参考这篇文章。

理解ajax跨域设置 ContentType: application/json

在使用ajax跨域请求时,如果设置Header的ContentType为 application/json,它会发两次请求,第一次先发请求方法(Method)为OPTIONS的请求到服务器,这个请求会询问服务器支持那些请求方法(比如GET,POST)等。如果这个请求支持跨域的话,就会发送第二个请求,否则的话在控制台会报错,第二个请求不会请求。如下我们做个简单的demo,不跨域的如下:
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
  <script type="text/javascript" src="/js/jquery.js"></script>
</head>
<body>
  <div id="app">
    <div class="btn">发送post请求</div>
  </div>
  <script>
    $('.btn').click(function() {
      $.ajax({
        url: 'http://localhost:8081/api',
        type: 'POST',
        dataType: 'json',
        contentType: 'application/json',
        data: JSON.stringify({a: [{b:1, a:1}]}),
        success: function(d) {}
      })
    });
  </script>
</body>
</html>

text/xml

XML-RPC(XML Remote Procedure Call),它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:
POST http://www.example.com HTTP/1.1
Content-Type: text/xml

<?xml version="1.0"?>
<methodCall>
    <methodName>examples.getStateName</methodName>
    <params>
        <param>
            <value><i4>41</i4></value>
        </param>
    </params>
</methodCall>

XML-RPC 协议简单、功能够用,各种语言的实现都有,且使用很广泛,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。在JavaScript中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过觉得 XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。

curl工具在测试接口时报Unsupported Media Type并返回错误

报错信息如下:
{"timestamp": "2020-12-06T22:37:18.184+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'text/plain;charset=UTF-8' not supported",
"path": "/test/freeoa.psp"
}

问题原因:Media Type,即是Internet Media Type,互联网媒体类型,也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。例如:Content-Type: text/html;charset:utf-8;

以上就是我们经常会用到的content-type的内容格式。通过此例中message信息,表示该post请求不支持"text/plain"纯文本格式类型,需要调整数据提交的格式。

解决办法:选择"application/json"以JSON数据格式类型发送post请求,成功得到接口返回值。即:curl -v -H "Content-type: application/json" -d '...' URL


小结一下HTTP常用消息头

HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行(对于请求消息,开始行就是请求行,对于响应消息,开始行就是状态行),消息报头(可选),空行(只有CRLF的行),消息正文(可选)组成。HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。每一个报头域都是由名字+":"+空格+值 组成,消息报头域的名字是大小写无关的。更多头信息请参考《http协议之header头》。

1、普通报头

在普通报头中有少数报头域用于所有的请求和响应消息,但并不用于被传输的实体,只用于传输的消息。

eg:Cache-Control 用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。

请求时的缓存指令包括:no-cache(用于指示请求或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached;

响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage.

eg:为了指示IE浏览器(客户端)不要缓存页面,服务器端的JSP程序可以编写如下:response.sehHeader("Cache-Control","no-cache");
//response.setHeader("Pragma","no-cache");作用相当于上述代码,通常两者//合用

这句代码将在发送的响应消息中设置普通报头域:Cache-Control:no-cache

Date普通报头域表示消息产生的日期和时间

Connection普通报头域允许发送指定连接的选项。例如指定连接是连续,或者指定“close”选项,通知服务器,在响应完成后,关闭连接

2、请求报头

请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。

常用的请求报头
Accept
Accept请求报头域用于指定客户端接受哪些类型的信息。eg:Accept:image/gif,表明客户端希望接受GIF图象格式的资源;Accept:text/html,表明客户端希望接受html文本。

Accept-Charset
Accept-Charset请求报头域用于指定客户端接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。

Accept-Encoding
Accept-Encoding请求报头域类似于Accept,但是它是用于指定可接受的内容编码。eg:Accept-Encoding:gzip.deflate.如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。

Accept-Language
Accept-Language请求报头域类似于Accept,但是它是用于指定一种自然语言。eg:Accept-Language:zh-cn.如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。

Authorization
Authorization请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进行验证。

Host(发送请求时,该报头域是必需的)
Host请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的,eg:在浏览器中输入:http://www.guet.edu.cn/index.html

浏览器发送的请求消息中,就会包含Host请求报头域,如下:
Host:www.guet.edu.cn

此处使用缺省端口号80,若指定了端口号,则变成:Host:www.guet.edu.cn:指定端口号

User-Agent
上网登陆论坛的时候,往往会看到一些欢迎信息,其中列出了你的操作系统的名称和版本,所使用的浏览器的名称和版本,这往往让很多人感到很神奇,实际上,服务器应用程序就是从User-Agent这个请求报头域中获取到这些信息。User-Agent请求报头域允许客户端将它的操作系统、浏览器和其它属性告诉服务器。不过,这个报头域不是必需的,如果自己编写一个浏览器,不使用User-Agent请求报头域,那么服务器端就无法得知我们的信息了。

请求报头举例:
GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
Host:www.guet.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)

3、响应报头

响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和对Request-URI所标识的资源进行下一步访问的信息。

常用的响应报头
Location
Location响应报头域用于重定向接受者到一个新的位置。Location响应报头域常用在更换域名的时候。

Server
Server响应报头域包含了服务器用来处理请求的软件信息。与User-Agent请求报头域是相对应的。下面是
Server响应报头域的一个例子:
Server:Apache-Coyote/1.1

WWW-Authenticate
WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,客户端收到401响应消息时候,并发送Authorization报头域请求服务器对其进行验证时,服务端响应报头就包含该报头域。

eg:WWW-Authenticate:Basic realm="Basic Auth Test!" //可以看出服务器对请求资源采用的是基本验证机制。

Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名。具体的定义如下 Content-Disposition: attachment; filename=“filename.xls”

当然filename参数可以包含路径信息,但User-Agnet会忽略掉这些信息,只会把路径信息的最后一部分做为文件名。当你在响应类型为application/octet- stream情况下使用了这个头信息的话,那就意味着你不想直接显示内容,而是弹出一个”文件下载”的对话框,接下来就是由你来决定“打开”还是“保存”了。

4、实体报头

请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送实体报头域。实体报头定义了关于实体正文(eg:有无实体正文)和请求所标识的资源的元信息。

常用的实体报头
Content-Encoding
Content-Encoding实体报头域被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding这样用于记录文档的压缩方法,eg:Content-Encoding: gzip

Content-Language
Content-Language实体报头域描述了资源所用的自然语言。没有设置该域则认为实体内容将提供给所有的语言阅读
者。eg:Content-Language:da

Content-Length
Content-Length实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示。

Content-Type
Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。eg:
Content-Type:text/html;charset=ISO-8859-1
Content-Type:text/html;charset=GBK

Last-Modified
Last-Modified实体报头域用于指示资源的最后修改日期和时间。

Expires
Expires 实体报头域给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,我们可以使用Expires实体报头域指定页面过期的时间。eg:Expires:Thu,15 Sep 2006 16:23:12 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。eg:为了让浏览器不要缓存页面,我们也可以利用Expires实体报头域,设置为0,jsp中程序如下:response.setDateHeader("Expires","0");


数据交互的实质是实体的通信,并以此派生出四种实时通信技术:短轮询、长轮询、WebSocket和SSE,来一起盘点一下。

1、短轮询
浏览器定时(如每秒)向服务器发送 HTTP 请求,服务器立即返回当前数据(无论是否有更新)。



优点:实现简单,兼容性极佳
缺点:高频请求浪费资源,实时性差(依赖轮询间隔)
延迟:高(取决于轮询频率)
适用场景:兼容性要求高,延迟不敏感的简单场景。

这种方式实现起来非常简单可靠,但是频繁的调用后端接口,会对后端性能会有影响(主要是 CPU)。同时因依赖轮询间隔,页面数据变化有延迟,用户体验并不算太好。

2、长轮询
浏览器发送 HTTP 请求后,服务器 挂起连接 直到数据更新或超时,返回响应后浏览器立即发起新请求。



优点:减少无效请求,比短轮询实时性更好
缺点:服务器需维护挂起连接,高并发时资源消耗大
延迟:中(取决于数据更新频率)
适用场景:需要较好实时性且无法用 WebSocket/SSE 的场景(如消息通知)
长轮询最常见的应用场景是:配置中心,我们耳熟能详的注册中心 Nacos 、阿波罗都是依赖长轮询机制。


nacos长轮询

客户端发起请求后,Nacos 服务端不会立即返回请求结果,而是将请求挂起等待一段时间,如果此段时间内服务端数据变更,立即响应客户端请求,若是一直无变化则等到指定的超时时间后响应请求,客户端重新发起长链接。

3、WebSocket
基于 TCP 的全双工协议,通过 HTTP 升级握手(Upgrade: websocket )建立持久连接,双向实时通信。



优点:最低延迟,支持双向交互,节省带宽
缺点:实现复杂,需单独处理连接状态
延迟:极低
适用场景:聊天室、在线游戏、协同编辑等高实时双向交互


4、Server Send Event(SSE)
基于 HTTP 协议,服务器可 主动推送数据流(如 Content-Type: text/event-stream),浏览器通过 EventSource API 监听。



优点:原生支持断线重连,轻量级(HTTP 协议)
缺点:不支持浏览器向服务器发送数据
延迟:低(服务器可即时推送)
适用场景:股票行情、实时日志等 服务器单向推送 需求。


5、小结
| 特性 | 短轮询 | 长轮询 | SSE | WebSocket |
| 通信方向 | 浏览器→服务器 | 浏览器→服务器 | 服务器→浏览器 | 双向通信 |
| 协议 | HTTP | HTTP | HTTP | WebSocket(基于 TCP) |
| 实时性 | 低 | 中 | 高 | 极高 |
| 资源消耗 | 高(频繁请求) | 中(挂起连接) | 低 | 低(长连接) |

选择建议:

需要 简单兼容性 → 短轮询
需要 中等实时性 → 长轮询
只需 服务器推送 → SSE
需要 全双工实时交互 → WebSocket


本文总结自互联网,感谢众多网友。