当前位置: 首页 > news >正文

HTTP相关面试题

HTTP/1.1、HTTP/2、HTTP/3 演变

HTTP/1.1 相比 HTTP/1.0 提高了什么性能?

HTTP/1.1 相⽐ HTTP/1.0 性能上的改进:

  • 使⽤长连接的⽅式改善了 HTTP/1.0 短连接造成的性能开销。
  • ⽀持管道(pipeline)网络传输,只要第⼀个请求发出去了,不必等其回来,就可以发第⼆个请求出去,可以减少整体的响应时间。

但 HTTP/1.1 还是有性能瓶颈:

  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越⼤。只能压缩 Body 的部 分;
  • 发送冗长的⾸部。每次互相发送相同的⾸部造成的浪费较多;
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客⼾端⼀直请求不到数据,也就是 队头阻塞;
  • 没有请求优先级控制;
  • 请求只能从客⼾端开始,服务器只能被动响应。

HTTP/2 做了什么优化?

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。

那 HTTP/2 相⽐ HTTP/1.1 性能上的改进:

  • 头部压缩
  • ⼆进制格式
  • 并发传输
  • 服务器主动推送资源

头部压缩

HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是⼀样的或是相似的,那么,协 议会帮你消除重复的部分。 这就是所谓的 HPACK 算法:在客⼾端和服务器同时维护⼀张头信息表,所有字段都会存⼊这个 表,⽣成⼀个索引号,以后就不发送同样字段了,只发送索引号,这样就提⾼速度了。

二进制格式

HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧(Headers Frame)和数据帧(Data Frame)

并发传输

我们都知道 HTTP/1.1 的实现是基于请求-响应模型的。同⼀个连接中,HTTP 完成⼀个事务(请求 与响应),才能处理下⼀个事务,也就是说在发出请求等待响应的过程中,是没办法做其他事情 的,如果响应迟迟不来,那么后续的请求是⽆法发送的,也造成了队头阻塞的问题。

⽽ HTTP/2 就很⽜逼了,引出了 Stream 概念,多个 Stream 复⽤在⼀条 TCP 连接。

1 个 TCP 连接包含多个 Stream,Stream ⾥可以包含 1 个或多个 Message, Message 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成。Message ⾥包含⼀条或者多 个 Frame,Frame 是 HTTP/2 最⼩单位,以⼆进制压缩格式存放 HTTP/1 中的内容(头部和包体)。

针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交错地发送请求和响应。

服务器主动推动

HTTP/2 还在⼀定程度上改善了传统的「请求 - 应答」⼯作模式,服务端不再是被动地响应,可以 主动向客⼾端发送消息。

客⼾端和服务器双方都可以建立Stream, Stream ID 也是有区别的,客⼾端建⽴的 Stream 必须 是奇数号,⽽服务器建⽴的 Stream 必须是偶数号

HTTP/2 有什么缺陷?

HTTP/2 通过 Stream 的并发能⼒,解决了 HTTP/1 队头阻塞的问题,看似很完美了,但是 HTTP/2 还是存在“队头阻塞”的问题,只不过问题不是在 HTTP 这⼀层⾯,⽽是在 TCP 这⼀层。

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区⾥的数据返回给 HTTP 应⽤,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区⾥,只有等到这 1 个字节数据到达时, HTTP/2 应⽤层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。

所以,一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来

HTTP/3 做了哪些优化?

前面我们知道了 HTTP/1.1 和 HTTP/2 都有队头阻塞的问题:

  • HTTP/1.1 中的管道( pipeline)虽然解决了请求的队头阻塞,但是没有解决响应的队头阻塞, 因为服务端需要按顺序响应收到的请求,如果服务端处理某个请求消耗的时间⽐较⻓,那么只 能等响应完这个请求后, 才能处理下⼀个请求,这属于 HTTP 层队头阻塞。
  • HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,但是一旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。

HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP

UDP 发送是不管顺序,也不管丢包的,所以不会出现像 HTTP/2 队头阻塞的问题。⼤家都知道 UDP 是不可靠传输的,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠性传输。

QUIC 有以下 3 个特点。

  • ⽆队头阻塞
  • 更快的连接建⽴
  • 连接迁移

无队头阻塞

QUIC 有⾃⼰的⼀套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他 流不会受到影响,因此不存在队头阻塞问题。这与 HTTP/2 不同,HTTP/2 只要某个流中的数据包 丢失了,其他流也会因此受影响。

所以,QUIC 连接上的多个 Stream 之间并没有依赖,都是独⽴的,某个流发⽣丢包了,只会影响 该流,其他流不受影响。

更快的连接建立

对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表⽰层,因此它们难以合并在⼀起,需要分批次来握⼿,先 TCP 握⼿,再 TLS 握⼿。

HTTP/3 在传输数据前虽然需要 QUIC 协议握⼿,但是这个握⼿过程只需要 1 RTT,握⼿的⽬的是 为确认双⽅的「连接 ID」,连接迁移就是基于连接 ID 实现的。

但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,⽽是 QUIC 内部包含了 TLS,它在⾃⼰的帧会携带 TLS ⾥的“记录”,再加上 QUIC 使⽤的是 TLS/1.3,因此仅需 1 个 RTT 就可以「同时」完成建⽴连接与密钥协商。

连接迁移

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端⼝、⽬的 IP、⽬的端⼝)确定 ⼀条 TCP 连接。

那么当移动设备的网络从流量切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建⽴连接。⽽建⽴连接的过程包含 TCP 三次握⼿和 TLS 四次握⼿的时延,以及 TCP 慢启动的减速过程,给⽤⼾的感觉就是⽹络突然卡顿了⼀下,因此连接的迁移成本是很⾼的。

⽽ QUIC 协议没有⽤四元组的⽅式来“绑定”连接,⽽是通过连接 ID 来标记通信的两个端点,客⼾ 端和服务器可以各⾃选择⼀组 ID 来标记⾃⼰,因此即使移动设备的⽹络变化后,导致 IP 地址变化 了,只要仍保有上下⽂信息(⽐如连接 ID、TLS 密钥等),就可以“⽆缝”地复⽤原连接,消除重连 的成本,没有丝毫卡顿感,达到了连接迁移的功能。

所以, QUIC 是⼀个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议。

与常用通信协议的区别

HTTP 和 RPC 的区别

TCP 是传输层的协议,而基于 TCP 造出来的 HTTP 和各类 RPC 协议,它们都只是定义了不同消息格式的应用层协议而已。

定义

  • HTTP 协议(Hyper Text Transfer Protocol),⼜叫做超⽂本传输协议。我们⽤的⽐较多,平时上⽹在浏览器上敲个⽹址就能访问⽹⻚,这⾥⽤到的就是 HTTP 协议。
  • 而RPC(Remote Procedure Call),⼜叫做远程过程调⽤。它本⾝并不是⼀个具体的协议,⽽是⼀ 种调⽤⽅式。

设计目标

  • HTTP主要用于跨平台、跨语言的交互
  • RPC主要用于内部系统高性能通信

服务发现

服务发现就是确定服务对应的IP和端口

  • 在 HTTP 中,你知道服务的域名,就可以通过 DNS 服务去解析得到它背后的 IP 地址,默认 80 端 ⼝。
  • 而 RPC 的话,就有些区别,⼀般会有专⻔的中间服务去保存服务名和IP信息,⽐如 Consul 或者 Etcd,甚⾄是 Redis。想要访问某个服务,就去这些中间服务去获得 IP 和端⼝信息。由于 DNS 也 是服务发现的⼀种,所以也有基于 DNS 去做服务发现的组件,⽐如CoreDNS。

底层连接形式

  • 以主流的 HTTP/1.1 协议为例,其默认在建⽴底层 TCP 连接之后会⼀直保持这个连接(Keep Alive),之后的请求和响应都会复⽤这条连接。
  • ⽽ RPC 协议,也跟 HTTP 类似,也是通过建⽴ TCP ⻓链接进⾏数据交互,但不同的地⽅在于, RPC 协议⼀般还会再建个连接池,在请求量⼤的时候,建⽴多条连接放在池内,要发数据的时候 就从池⾥取⼀条连接出来,⽤完放回去,下次再复⽤,可以说⾮常环保。

由于连接池有利于提升网络请求性能,所以不少编程语言的网络库里都会给 HTTP 加个连接池,比如 Go 就是这么干的。

传输的内容

  • RPC通常使用二进制协议和高效的序列化格式,性能较高。
  • 由于基于文本协议(HTTP/1.x),性能相对较低,尤其是在高并发场景下。HTTP/2 和 HTTP/3 通过二进制协议和多路复用等技术提升了性能。

HTTP 和 WebSocket 的区别

通信模式

  • HTTP请求-响应模型:客户端发送请求,服务器返回响应,通信是单向的。每次请求都需要建立和关闭连接(HTTP/1.x),或者通过持久连接复用(HTTP/2)。半双工通信。
  • WebSocket全双工通信:客户端和服务器之间建立持久连接,双方可以随时发送消息。通信是双向的,适合实时交互场景。

连接生命周期

  • WebSocket:建立连接后,客户端和服务器可以保持长连接,直到显式关闭。连接建立后,通信开销较低,适合频繁的数据交换。
  • HTTP:在 HTTP/1.x 中,每次请求都需要建立和关闭连接,导致较高的开销。在 HTTP/2 中,支持多路复用,可以在一个连接上并行处理多个请求。

使用场景

  • HTTP:适用于 Web 页面加载、RESTful API、文件传输等场景。适合一次性请求-响应的交互模式。
  • WebSocket:适用于实时通信场景,如在线聊天、实时通知、在线游戏、股票行情等。适合需要频繁双向通信的场景。

协议升级

  • WebSocket 连接的建立需要通过 HTTP 协议进行升级。
  • 客户端发送一个 HTTP 请求,包含 Upgrade: websocket 头部,服务器同意升级后,连接转换为 WebSocket 协议。

SSE(Server-Sent Events)与 HTTP 的区别

定义

  • HTTP(HyperText Transfer Protocol)
    • 是一种应用层协议,主要用于在 Web 浏览器和服务器之间传输超文本(如 HTML)。
    • 基于请求-响应模型,通常使用 TCP 作为传输层协议。
  • SSE(Server-Sent Events)
    • 是一种基于 HTTP 的单向通信机制,允许服务器向客户端推送实时事件。
    • 设计目标是实现服务器到客户端的单向实时通信。

通信模式

  • HTTP
    • 请求-响应模型:客户端发送请求,服务器返回响应,通信是单向的。
    • 每次请求都需要建立和关闭连接(HTTP/1.x),或者通过持久连接复用(HTTP/2)。
  • SSE
    • 单向推送模型:客户端发起连接后,服务器可以持续向客户端推送事件。
    • 通信是单向的,适合服务器向客户端推送实时数据。

3. 连接生命周期

  • HTTP
    • 在 HTTP/1.x 中,每次请求都需要建立和关闭连接,导致较高的开销。
    • 在 HTTP/2 中,支持多路复用,可以在一个连接上并行处理多个请求。
  • SSE
    • 建立连接后,服务器可以持续向客户端推送事件,直到显式关闭。
    • 连接是持久的,适合服务器主动推送数据的场景。

相关文章:

HTTP相关面试题

HTTP/1.1、HTTP/2、HTTP/3 演变 HTTP/1.1 相比 HTTP/1.0 提高了什么性能? HTTP/1.1 相⽐ HTTP/1.0 性能上的改进: 使⽤长连接的⽅式改善了 HTTP/1.0 短连接造成的性能开销。⽀持管道(pipeline)网络传输,只要第⼀个请…...

关于XML映射器的基本问题

前言 XML 映射器是 MyBatis 中用于定义 SQL 语句及其与 Java 对象映射关系的 XML 文件。它通过 XML 配置将数据库操作与 Java 代码分离,使 SQL 语句更易维护和管理。 主要作用 定义 SQL 语句:在 XML 中编写 SQL 查询、插入、更新和删除操作。 映射结果…...

【MyBatis】预编译SQL与即时SQL

目录 1. 以基本类型参数为例测试#{ }与${ }传递参数的区别 1.1 参数为Integer类型 1.2 参数为String类型 2. 使用#{ }传参存在的问题 2.1 参数为排序方式 2.2 模糊查询 3. 使用${ }传参存在的问题 3.1 SQL注入 3.2 对比#{ } 与 ${ }在SQL注入方面存在的问题 3.3 预编译…...

Python--正则表达式

1. 日志打印与终端颜色控制 1.1 使用 loguru​ 打印日志 from loguru import loggerlogger.debug("调试信息") logger.info("普通信息") logger.warning("警告信息") logger.error("错误信息") logger.success("成功信息"…...

【java面试】线程篇

1.什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 2.线程和进程有什么区别? 线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任…...

分布式光纤传感:为生活编织“感知密网”

分布式光纤测温技术虽以工业场景为核心,但其衍生的安全效益已逐步渗透至日常生活。 分布式光纤测温技术(DTS)作为一种先进的线型温度监测手段,近年来在多个领域展现了其独特的优势。虽然其核心应用场景主要集中在工业、能源和基础…...

cmake Qt Mingw windows构建

今天教大家怎么在windows构建qt应用使用cmd命令行,而不是一键通过QtCreator一键构建。首先我们用qtcreator创建一个模板程序(PS:记得在安装qt时要悬着mingw套件,如果安装太慢可以换源) 输入以下的命令: mkdir build …...

无人机信号调制技术原理

一、调制技术的必要性 频谱搬移:将低频的基带信号搬移到高频的载波上,便于天线辐射和传播。 信道复用: 利用不同的载波频率或调制方式,实现多路信号同时传输,提高信道利用率。 抗干扰: 通过选择合适的调…...

书评与笔记:《如何有效报告Bug》

文章目录 书评笔记核心原则1. 首要目标:让程序员亲眼看到问题2. 次要目标:详细描述问题3. 保持冷静,避免误操作4. 提供额外信息5. 清晰、准确地表达 实用建议不要自作聪明地诊断问题类比:看医生时的症状描述程序员的心理 总结 原文…...

3.【线性代数】——矩阵乘法和逆矩阵

三 矩阵乘法和逆矩阵 1. 矩阵乘法1.1 常规方法1.2 列向量组合1.3 行向量组合1.4 单行和单列的乘积和1.5 块乘法 2. 逆矩阵2.1 逆矩阵的定义2.2 奇异矩阵2.3 Gauss-Jordan 求逆矩阵2.3.1 求逆矩阵 ⟺ \Longleftrightarrow ⟺解方程组2.3.2 Gauss-Jordan求逆矩阵 1. 矩阵乘法 1.…...

[JVM篇]虚拟机性能监控、故障处理工具

虚拟机性能监控、故障处理工具 基础故障处理工具 jps(JVM Peocess Status Tool - 虚拟机进程状况工具) jstat(JVM Statistics Monitoring Too - 虚拟机统计信息监视工具) jinfo( Configuration info for Java - Java配置信息工具) jmap(Memory Map for…...

UniApp 中 margin 和 padding 属性的使用详解

margin 属性的作用与使用 margin 属性用于设置元素的外边距&#xff0c;也就是元素与其他元素之间的距离。它可以分别设置元素四个方向&#xff08;上、右、下、左&#xff09;的外边距&#xff0c;也支持使用简写形式来一次性设置多个方向的外边距。 <template><view…...

`fi` 是 Bash 脚本中用来结束 `if` 条件语句块的关键字

fi 是 Bash 脚本中 if 语句的结束标志&#xff0c;它用于结束一个 if 块。与其他编程语言&#xff08;如 C、Java&#xff09;中的 } 不同&#xff0c;Bash 使用 fi 来标识条件语句的结束。 语法示例&#xff1a; if [ condition ]; then# 如果条件为真时执行的代码echo &quo…...

cap2:1000分类的ResNet的TensorRT部署指南(python版)

《TensorRT全流程部署指南》专栏文章目录&#xff1a; cap1&#xff1a;TensorRT介绍及CUDA环境安装cap2&#xff1a;1000分类的ResNet的TensorRT部署指南&#xff08;python版&#xff09;cap3&#xff1a;自定义数据集训练ResNet的TensorRT部署指南&#xff08;python版&…...

每日一题——把数字翻译成字符串

把数字翻译成字符串 题目描述示例示例1示例2 题解动态规划代码实现复杂度分析 总结 题目描述 有一种将字母编码成数字的方式&#xff1a;‘a’->1, ‘b’->2, … , ‘z’->26。 现在给一串数字&#xff0c;返回有多少种可能的译码结果。 数据范围&#xff1a;字符串…...

我们来学HTTP/TCP -- 三次握手?

三次握手 题记三次呼叫结语 题记 来&#xff0c;我们来演示下川普王和普京帝会面了 哎呦&#xff01;你好你好&#xff0c;握手…哎嗨&#xff01;侬好侬好&#xff0c;握手…欧嘿呦玛斯&#xff0c;握手… 抓狂啊&#xff01;作孽啊!!! 不说人话啊! 关键的是&#xff0c;“三…...

多媒体软件安全与授权新范例,用 CodeMeter 实现安全、高效的软件许可管理

背景概述 Reason Studios 成立于 1994 年&#xff0c;总部位于瑞典斯德哥尔摩&#xff0c;是全球领先的音乐制作软件开发商。凭借创新的软件产品和行业标准技术&#xff0c;如 ReWire 和 REX 文件格式&#xff0c;Reason Studios 为全球专业音乐人和业余爱好者提供了一系列高质…...

SQL复习

SQL复习 MySQL MySQL MySQL有什么特点&#xff1f; MySQL 不支持全外连接。 安装 数据类型 MySQL中的数据类型分为哪些&#xff1f; MySQL中的数据类型主要分为三大类&#xff1a;数值类型、字符串类型、日期时间类型。 其中&#xff0c; 数值类型又分为七种&#xff1a;T…...

红队视角出发的k8s敏感信息收集——日志与监控系统

针对 Kubernetes 日志与监控系统 的详细攻击视角分析&#xff0c;聚焦 集群审计日志 和 Prometheus/Grafana 暴露 的潜在风险及利用方法 攻击链示例 1. 攻击者通过容器逃逸进入 Pod → 2. 发现未认证的 Prometheus 服务 → 3. 查询环境变量标签获取数据库密码 → 4. 通过审…...

Flask中获取请求参数的一些方式总结

在 Flask 中&#xff0c;可以从 request 对象中获取各种类型的参数。以下是全面整理的获取参数的方式及示例代码。 1. 获取 URL 查询参数&#xff08;Query String Parameters&#xff09; URL 中的查询参数通过 ?keyvalue&key2value2 的形式传递&#xff0c;使用 reques…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...