HTTP协议

1、HTTP的前世今生

HTTP 协议始于三十年前蒂姆·伯纳斯 - 李的一篇论文;

HTTP/0.9 是个简单的文本协议,只能获取文本资源;

HTTP/1.0 确立了大部分现在使用的技术,但它不是正式标准;

HTTP/1.1 是目前互联网上使用最广泛的协议,功能也非常完善;

HTTP/2 基于 Google 的 SPDY 协议,注重性能改善,但还未普及;

HTTP/3 基于 Google 的 QUIC 协议,是将来的发展方向。

2、HTTP是什么

HTTP 是一个用在计算机世界里的协议,它确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。

HTTP 专门用来在两点之间传输数据,不能用于广播、寻址或路由。

HTTP 传输的是文字、图片、音频、视频等超文本数据。

HTTP 是构建互联网的重要基础技术,它没有实体,依赖许多其他的技术来实现,但同时许多技术也都依赖于它。

3、与HTTP相关的各种概念

互联网上绝大部分资源都使用 HTTP 协议传输;

浏览器是 HTTP 协议里的请求方,即 User Agent;

服务器是 HTTP 协议里的应答方,常用的有 Apache 和 Nginx;

CDN 位于浏览器和服务器之间,主要起到缓存加速的作用;

爬虫是另一类 User Agent,是自动访问网络资源的程序。

4、与HTTP相关的各种协议

TCP/IP 是网络世界最常用的协议,HTTP 通常运行在 TCP/IP 提供的可靠传输基础上;

DNS 域名是 IP 地址的等价替代,需要用域名解析实现到 IP 地址的映射;

URI 是用来标记互联网上资源的一个名字,由“协议名 + 主机名 + 路径”构成,俗称 URL;

HTTPS 相当于“HTTP+SSL/TLS+TCP/IP”,为 HTTP 套了一个安全的外壳;

代理是 HTTP 传输过程中的“中转站”,可以实现缓存加速、负载均衡等功能。

TCP/IP 分为四层,核心是二层的 IP 和三层的 TCP,HTTP 在第四层;

OSI 分为七层,基本对应 TCP/IP,TCP 在第四层,HTTP 在第七层;

OSI 可以映射到 TCP/IP,但这期间一、五、六层消失了;

日常交流的时候我们通常使用 OSI 模型,用四层、七层等术语;

HTTP 利用 TCP/IP 协议栈逐层打包再拆包,实现了数据传输,但下面的细节并不可见。

有一个辨别四层和七层比较好的(但不是绝对的)小窍门,“两个凡是”:凡是由操作系统负责处理的就是四层或四层以下,否则,凡是需要由应用程序(也就是你自己写代码)负责处理的就是七层。

5、域名里有哪些门道?

域名使用字符串来代替 IP 地址,方便用户记忆,本质上一个名字空间系统;

DNS 就像是我们现实世界里的电话本、查号台,统管着互联网世界里的所有网站,是一个“超级大管家”;

DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存;

使用 DNS 可以实现基于域名的负载均衡,既可以在内网,也可以在外网。

6、搭建HTTP实验环境

现实的网络环境太复杂,有很多干扰因素,搭建“最小化”的环境可以快速抓住重点,掌握 HTTP 的本质;

我们选择 Wireshark 作为抓包工具,捕获在 TCP/IP 协议栈中传输的所有流量;

我们选择 Chrome 或 Firefox 浏览器作为 HTTP 协议中的 user agent;

我们选择 OpenResty 作为Web服务器,它是一个Nginx的“强化包”,功能非常丰富;

Telnet 是一个命令行工具,可用来登录主机模拟浏览器操作;

在 GitHub 上可以下载到本专栏的专用项目源码,只要把 OpenResty 解压到里面即可完成实验环境的搭建。

7、键入网址再按下回车,后面究竟发生了什么?

HTTP 协议基于底层的 TCP/IP 协议,所以必须要用 IP 地址建立连接;

如果不知道 IP 地址,就要用 DNS 协议去解析得到 IP 地址,否则就会连接失败;

建立 TCP 连接后会顺序收发数据,请求方和应答方都必须依据 HTTP 规范构建和解析报文;

为了减少响应时间,整个过程中的每一个环节都会有缓存,能够实现“短路”操作;

虽然现实中的 HTTP 传输过程非常复杂,但理论上仍然可以简化成实验里的“两点”模型。

8、HTTP报文是什么样子

HTTP 报文结构就像是“大头儿子”,由“起始行 + 头部 + 空行 + 实体”组成,简单地说就是“header+body”;

HTTP 报文可以没有 body,但必须要有 header,而且 header 后也必须要有空行,形象地说就是“大头”必须要带着“脖子”;

请求头由“请求行 + 头部字段”构成,响应头由“状态行 + 头部字段”构成;

请求行有三部分:请求方法,请求目标和版本号;

状态行也有三部分:版本号,状态码和原因字符串;

头部字段是 key-value 的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;

HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。

9、如何理解请求方法?

请求方法是客户端发出的、要求服务器执行的、对资源的一种操作;

请求方法是对服务器的“指示”,真正应如何处理由服务器来决定;

最常用的请求方法是 GET 和 POST,分别是获取数据和发送数据;

HEAD 方法是轻量级的 GET,用来获取资源的元信息;

PUT 基本上是 POST 的同义词,多用于更新数据;

“安全”与“幂等”是描述请求方法的两个重要属性,具有理论指导意义,可以帮助我们设计系统。

10、写出正确的网址

URI 是用来唯一标记服务器上资源的一个字符串,通常也称为 URL;

URI 通常由 scheme、host:port、path 和 query 四个部分组成,有的可以省略;

scheme 叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问;

“host:port”表示资源所在的主机名和端口号;

path 标记资源所在的位置;

query 表示对资源附加的额外要求;

在 URI 里对“@&/”等特殊字符和汉字必须要做编码,否则服务器收到 HTTP 报文后会无法正确处理。

11、响应状态码

(1)、状态码类别:

1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;

2××:成功,报文已经收到并被正确处理;

3××:重定向,资源位置发生变动,需要客户端重新发送请求;

4××:客户端错误,请求报文有误,服务器无法处理;

5××:服务器错误,服务器在处理请求时内部发生了错误。

(2)、状态码说明:

状态码在响应报文里表示了服务器对请求的处理结果;

状态码后的原因短语是简单的文字描述,可以自定义;

状态码是十进制的三位数,分为五类,从 100 到 599;

2××类状态码表示成功,常用的有 200、204、206;

3××类状态码表示重定向,常用的有 301、302、304;

4××类状态码表示客户端错误,常用的有 400、403、404;

5××类状态码表示服务器错误,常用的有 500、501、502、503。
12、HTTP有哪些特点

HTTP 是灵活可扩展的,可以任意添加头字段实现任意功能;

HTTP 是可靠传输协议,基于 TCP/IP 协议“尽量”保证数据的送达;

HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据;

HTTP 使用了请求 - 应答模式,客户端主动发起请求,服务器被动回复请求;

HTTP 本质上是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。

13、HTTP优点、缺点

HTTP 最大的优点是简单、灵活和易于扩展;

HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施;

HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”;

HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听;

HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改;

HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间。

14、HTTP的实体数据

数据类型表示实体数据的内容是什么,使用的是 MIME type,相关的头字段是 Accept 和 Content-Type;

数据编码表示实体数据的压缩方式,相关的头字段是 Accept-Encoding 和 Content-Encoding;

语言类型表示实体数据的自然语言,相关的头字段是 Accept-Language 和 Content-Language;

字符集表示实体数据的编码方式,相关的头字段是 Accept-Charset 和 Content-Type;

客户端需要在请求头里使用 Accept 等头字段与服务器进行“内容协商”,要求服务器返回最合适的数据;

Accept 等头字段可以用“,”顺序列出多个可能的选项,还可以用“;q=”参数来精确指定权重。

15、HTTP传输大文件的方法

压缩 HTML 等文本文件是传输大文件最基本的方法;

分块传输可以流式收发数据,节约内存和带宽,使用响应头字段“Transfer-Encoding: chunked”来表示,分块的格式是 16 进制长度头 + 数据块;

范围请求可以只获取部分数据,即“分块请求”,实现视频拖拽或者断点续传,使用请求头字段“Range”和响应头字段“Content-Range”,响应状态码必须是 206;

也可以一次请求多个范围,这时候响应报文的数据类型是“multipart/byteranges”,body 里的多个部分会用 boundary 字符串分隔。

要注意这四种方法不是互斥的,而是可以混合起来使用,例如压缩后再分块传输,或者分段后再分块,实验环境的 URI“/16-3”就模拟了后一种的情形,你可以自己用 Telnet 试一下。

16、HTTP 协议里的短连接和长连接

早期的 HTTP 协议使用短连接,收到响应后就立即关闭连接,效率很低;

HTTP/1.1 默认启用长连接,在一个连接上收发多个请求响应,提高了传输效率;

服务器会发送“Connection: keep-alive”字段表示启用了长连接;

报文头里如果有“Connection: close”就意味着长连接即将关闭;

过多的长连接会占用服务器资源,所以服务器会用一些策略有选择地关闭长连接;

“队头阻塞”问题会导致性能下降,可以用“并发连接”和“域名分片”技术缓解。

17、HTTP的重定向和跳转

重定向是服务器发起的跳转,要求客户端改用新的 URI 重新发送请求,通常会自动进行,用户是无感知的;

301/302 是最常用的重定向状态码,分别是“永久重定向”和“临时重定向”;

响应头字段 Location 指示了要跳转的 URI,可以用绝对或相对的形式;

重定向可以把一个 URI 指向另一个 URI,也可以把多个 URI 指向同一个 URI,用途很多;

使用重定向时需要当心性能损耗,还要避免出现循环跳转。

18、HTTP的Cookie机制

Cookie 是服务器委托浏览器存储的一些数据,让服务器有了“记忆能力”;

响应报文使用 Set-Cookie 字段发送“key=value”形式的 Cookie 值;

请求报文里用 Cookie 字段发送多个 Cookie 值;

为了保护 Cookie,还要给它设置有效期、作用域等属性,常用的有 Max-Age、Expires、Domain、HttpOnly 等;

Cookie 最基本的用途是身份识别,实现有状态的会话事务。

19、HTTP的缓存控制

缓存是优化系统性能的重要手段,HTTP 传输的每一个环节中都可以有缓存;

服务器使用“Cache-Control”设置缓存策略,常用的是“max-age”,表示资源的有效期;

浏览器收到数据就会存入缓存,如果没过期就可以直接使用,过期就要去服务器验证是否仍然可用;

验证资源是否失效需要使用“条件请求”,常用的是“if-Modified-Since”和“If-None-Match”,收到 304 就可以复用缓存里的资源;

验证资源是否被修改的条件有两个:“Last-modified”和“ETag”,需要服务器预先在响应报文里设置,搭配条件请求使用;

浏览器也可以发送“Cache-Control”字段,使用“max-age=0”或“no_cache”刷新数据。

HTTP 缓存看上去很复杂,但基本原理说白了就是一句话:“没有消息就是好消息”,“没有请求的请求,才是最快的请求。”

20、HTTP的代理服务

HTTP 代理就是客户端和服务器通信链路中的一个中间环节,为两端提供“代理服务”;

代理处于中间层,为 HTTP 处理增加了更多的灵活性,可以实现负载均衡、安全防护、数据过滤等功能;

代理服务器需要使用字段“Via”标记自己的身份,多个代理会形成一个列表;

如果想要知道客户端的真实 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”;

专门的“代理协议”可以在不改动原始报文的情况下传递客户端的真实 IP。

21、HTTP的缓存代理

计算机领域里最常用的性能优化手段是“时空转换”,也就是“时间换空间”或者“空间换时间”,HTTP 缓存属于后者;

缓存代理是增加了缓存功能的代理服务,缓存源服务器的数据,分发给下游的客户端;

“Cache-Control”字段也可以控制缓存代理,常用的有“private”“s-maxage”“no-transform”等,同样必须配合“Last-modified”“ETag”等字段才能使用;

缓存代理有时候也会带来负面影响,缓存不良数据,需要及时刷新或删除。

22、HTTPS、SSL/TLS

因为 HTTP 是明文传输,所以不安全,容易被黑客窃听或窜改;

通信安全必须同时具备机密性、完整性,身份认证和不可否认这四个特性;

HTTPS 的语法、语义仍然是 HTTP,但把下层的协议由 TCP/IP 换成了 SSL/TLS;

SSL/TLS 是信息安全领域中的权威标准,采用多种先进的加密技术保证通信安全;

OpenSSL 是著名的开源密码学工具包,是 SSL/TLS 的具体实现。

23、对称加密与非对称加密

加密算法的核心思想是“把一个小秘密(密钥)转化为一个大秘密(密文消息)”,守住了小秘密,也就守住了大秘密;

对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换,常用的有 AES 和 ChaCha20;

非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢,常用的有 RSA 和 ECC;

把对称加密和非对称加密结合起来就得到了“又好又快”的混合加密,也就是 TLS 里使用的加密方式。

24、数字签名与证书

摘要算法用来实现完整性,能够为数据生成独一无二的“指纹”,常用的算法是 SHA-2;

数字签名是私钥对摘要的加密,可以由公钥解密后验证,实现身份认证和不可否认;

公钥的分发需要使用数字证书,必须由 CA 的信任链来验证,否则就是不可信的;

作为信任链的源头 CA 有时也会不可信,解决办法有 CRL、OCSP,还有终止信任。

25、HTTPS/TLS 的握手

HTTPS 协议会先与服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接;

握手的目标是安全地交换对称密钥,需要三个随机数,第三个随机数“Pre-Master”必须加密传输,绝对不能让黑客破解;

“Hello”消息交换随机数,“Key Exchange”消息交换“Pre-Master”;

“Change Cipher Spec”之前传输的都是明文,之后都是对称密钥加密的密文。

为了兼容 1.1、1.2 等“老”协议,TLS1.3 会“伪装”成 TLS1.2,新特性在“扩展”里实现;

1.1、1.2 在实践中发现了很多安全隐患,所以 TLS1.3 大幅度删减了加密算法,只保留了 ECDHE、AES、ChaCha20、SHA-2 等极少数算法,强化了安全;

TLS1.3 也简化了握手过程,完全握手只需要一个消息往返,提升了性能。

26、HTTPS的优化

可以有多种硬件和软件手段减少网络耗时和计算耗时,让 HTTPS 变得和 HTTP 一样快,最可行的是软件优化;

应当尽量使用 ECDHE 椭圆曲线密码套件,节约带宽和计算量,还能实现“False Start”;

服务器端应当开启“OCSP Stapling”功能,避免客户端访问 CA 去验证证书;

会话复用的效果类似 Cache,前提是客户端必须之前成功建立连接,后面就可以用“Session ID”“Session Ticket”等凭据跳过密钥交换、证书验证等步骤,直接开始加密通信。

27、HTTPS 迁移的技术要点

但想要实现大型网站的“全站 HTTPS”还是需要有很多的细枝末节的工作要做,比如使用 CSP(Content Security Policy)的各种指令和标签来配置安全策略,使用反向代理来集中“卸载”SSL。

从 HTTP 迁移到 HTTPS 是“大势所趋”,能做就应该尽早做;

升级 HTTPS 首先要申请数字证书,可以选择免费好用的“Let’s Encrypt”;

配置 HTTPS 时需要注意选择恰当的 TLS 版本和密码套件,强化安全;

原有的 HTTP 站点可以保留作为过渡,使用 301 重定向到 HTTPS。

28、HTTP/2 的一些重要特性

HTTP 协议取消了小版本号,所以 HTTP/2 的正式名字不是 2.0;

HTTP/2 在“语义”上兼容 HTTP/1,保留了请求方法、URI 等传统概念;

HTTP/2 使用“HPACK”算法压缩头部信息,消除冗余数据节约带宽;

HTTP/2 的消息不再是“Header+Body”的形式,而是分散为多个二进制“帧”;

HTTP/2 使用虚拟的“流”传输消息,解决了困扰多年的“队头阻塞”问题,同时实现了“多路复用”,提高连接的利用率;

HTTP/2 也增强了安全性,要求至少是 TLS1.2,而且禁用了很多不安全的密码套件。

HTTP/2 必须先发送一个“连接前言”字符串,然后才能建立正式连接;

HTTP/2 废除了起始行,统一使用头字段,在两端维护字段“Key-Value”的索引表,使用“HPACK”算法压缩头部;

HTTP/2 把报文切分为多种类型的二进制帧,报头里最重要的字段是流标识符,标记帧属于哪个流;

流是 HTTP/2 虚拟的概念,是帧的双向传输序列,相当于 HTTP/1 里的一次“请求 - 应答”;

在一个 HTTP/2 连接上可以并发多个流,也就是多个“请求 - 响应”报文,这就是“多路复用”。

29、HTTP/3 展望

HTTP/3 综合了我们之前讲的所有技术(HTTP/1、SSL/TLS、HTTP/2),包含知识点很多,比如队头阻塞、0-RTT 握手、虚拟的“流”、多路复用,算得上是“集大成之作”,需要多下些功夫好好体会。

HTTP/3 基于 QUIC 协议,完全解决了“队头阻塞”问题,弱网环境下的表现会优于 HTTP/2;

QUIC 是一个新的传输层协议,建立在 UDP 之上,实现了可靠传输;

QUIC 内含了 TLS1.3,只能加密通信,支持 0-RTT 快速建连;

QUIC 的连接使用“不透明”的连接 ID,不绑定在“IP 地址 + 端口”上,支持“连接迁移”;

QUIC 的流与 HTTP/2 的流很相似,但分为双向流和单向流;

HTTP/3 没有指定默认端口号,需要用 HTTP/2 的扩展帧“Alt-Svc”来发现。

30、如何迁移到 HTTP/2。

HTTP/2 完全兼容 HTTP/1,是“更安全的 HTTP、更快的
HTTPS”,头部压缩、多路复用等技术可以充分利用带宽,降低延迟,从而大幅度提高上网体验;

TCP 协议存在“队头阻塞”,所以 HTTP/2 在弱网或者移动网络下的性能表现会不如 HTTP/1;

迁移到 HTTP/2 肯定会有性能提升,但高流量网站效果会更显著;

如果已经升级到了 HTTPS,那么再升级到 HTTP/2 会很简单;

TLS 协议提供“ALPN”扩展,让客户端和服务器协商使用的应用层协议,“发现”HTTP/2 服务。

31、Nginx 高性能的 Web 服务器

Nginx 是一个高性能的 Web 服务器,它非常的轻量级,消耗的 CPU、内存很少;

Nginx 采用“master/workers”进程池架构,不使用多线程,消除了进程、线程切换的成本;

Nginx 基于 epoll 实现了“I/O 多路复用”,不会阻塞,所以性能很高;

Nginx 使用了“职责链”模式,多个模块分工合作,自由组合,以流水线的方式处理 HTTP 请求。

32、OpenResty:更灵活的Web服务器

Nginx 依赖于磁盘上的静态配置文件,修改后必须重启才能生效,缺乏灵活性;

OpenResty 基于 Nginx,打包了很多有用的模块和库,是一个高性能的 Web 开发平台;

OpenResty 的工作语言是 Lua,它小巧灵活,执行效率高,支持“代码热加载”;

OpenResty 的核心编程范式是“同步非阻塞”,使用协程,不需要异步回调函数;

OpenResty 也使用“阶段式处理”的工作模式,但因为在阶段里执行的都是 Lua 代码,所以非常灵活,配合 Redis 等外部数据库能够实现各种动态配置。

33、WAF:保护我们的网络服务

Web 服务通常都运行在公网上,容易受到“DDoS”、“代码注入”等各种黑客攻击,影响正常的服务,所以必须要采取措施加以保护;

WAF 是一种“HTTP 入侵检测和防御系统”,工作在七层,为 Web 服务提供全面的防护

ModSecurity 是一个开源的、生产级的 WAF 产品,核心组成部分是“规则引擎”和“规则集”,两者的关系有点像杀毒引擎和病毒特征库;

WAF 实质上是模式匹配与数据过滤,所以会消耗 CPU,增加一些计算成本,降低服务能力,使用时需要在安全与性能之间找到一个“平衡点”。

34、CDN:加速我们的网络服务

由于客观地理距离的存在,直连网站访问速度会很慢,所以就出现了 CDN;

CDN 构建了全国、全球级别的专网,让用户就近访问专网里的边缘节点,降低了传输延迟,实现了网站加速;

GSLB 是 CDN 的“大脑”,使用 DNS 负载均衡技术,智能调度边缘节点提供服务;

缓存系统是 CDN 的“心脏”,使用 HTTP 缓存代理技术,缓存命中就返回给用户,否则就要回源。

35、WebSocket:沙盒里的TCP

浏览器是一个“沙盒”环境,有很多的限制,不允许建立 TCP 连接收发数据,而有了 WebSocket,我们就可以在浏览器里与服务器直接建立“TCP 连接”,获得更多的自由。

不过自由也是有代价的,WebSocket 虽然是在应用层,但使用方式却与“TCP Socket”差不多,过于“原始”,用户必须自己管理连接、缓存、状态,开发上比 HTTP 复杂的多,所以是否要在项目中引入 WebSocket 必须慎重考虑。

HTTP 的“请求 - 应答”模式不适合开发“实时通信”应用,效率低,难以实现动态页面,所以出现了 WebSocket;

WebSocket 是一个“全双工”的通信协议,相当于对 TCP 做了一层“薄薄的包装”,让它运行在浏览器环境里;

WebSocket 使用兼容 HTTP 的 URI 来发现服务,但定义了新的协议名“ws”和“wss”,端口号也沿用了 80 和 443;

WebSocket 使用二进制帧,结构比较简单,特殊的地方是有个“掩码”操作,客户端发数据必须掩码,服务器则不用;

WebSocket 利用 HTTP 协议实现连接握手,发送 GET 请求要求“协议升级”,握手过程中有个非常简单的认证机制,目的是防止误连接。

36、 HTTP性能优化面面观

性能优化是一个复杂的概念,在 HTTP 里可以分解为服务器性能优化、客户端性能优化和传输链路优化;

服务器有三个主要的性能指标:吞吐量、并发数和响应时间,此外还需要考虑资源利用率;

客户端的基本性能指标是延迟,影响因素有地理距离、带宽、DNS 查询、TCP 握手等;

从服务器到客户端的传输链路可以分为三个部分,我们能够优化的是前两个部分,也就是“第一公里”和“中间一公里”;

有很多工具可以测量这些指标,服务器端有 ab、top、sar 等,客户端可以使用测试网站,浏览器的开发者工具。

花钱购买硬件、软件或者服务可以直接提升网站的服务能力,其中最有价值的是 CDN;

不花钱也可以优化 HTTP,三个关键词是“开源”“节流”和“缓存”;

后端应该选用高性能的 Web 服务器,开启长连接,提升 TCP 的传输效率;

前端应该启用 gzip、br 压缩,减小文本、图片的体积,尽量少传不必要的头字段;

缓存是无论何时都不能忘记的性能优化利器,应该总使用 Etag 或 Last-modified 字段标记资源;

升级到 HTTP/2 能够直接获得许多方面的性能提升,但要留意一些 HTTP/1 的“反模式”。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值