HTTP协议

目录

什么是HTTP

HTTP协议抓包工具----Fiddler

抓包工具的原理

 Fiddler的安装

Fiddler的使用

HTTP请求(Request)

认识URL

URL基本格式

关于URL Encode

认识"方法"(method)

1.GET方法

2.POST方法

3.其他方法

认识请求头"报头"(header)

1.HOST

2.Content-Length

3.Content-Type

4.User-Agent(简称UA)

5.Referer

6.Cookie

请求格式

1)首行

2)请求头(header)

3)空行

4)正文(body)

HTTP响应(response)

认识"状态码"(statu code)

1.200 OK

2.404 Not Found

3.403 Forbidden

4.405 Method Not Allowed

5.500 Internal Server Error

6.504 Gateway Timeout

7.301 Moved Permanently

8.302 Move temporarily

认识响应"报头"(header)

响应格式

1)首行

2)响应头(header)

3)空行

4)正文(body)


什么是HTTP

HTTP,全称为"超文本传输协议",是一种应用非常广泛的应用层协议

HTTP往往是基于传输层的TCP协议实现的(HTTP1.0,HTTP1.1,HTTP2.0均为TCP,HTTP3.0是基于UDP实现的)。HTTP协议的最新版本是HTTP3.0,但目前大规模使用的是还是HTTP1.1,我们这篇文章讨论的也是以HTTP1.1版本为主。

使用HTTP协议的场景主要有两个:1.浏览器打开网站(基本上);2.手机APP访问对应的服务器(大概率)。

学习HTTP协议,重点学习的是HTTP的报文格式。与前面的TCP/IP/UDP不同,HTTP的报文格式要分为两个部分来看待,一个是请求,一个是响应。HTTP协议是一种"一问一答"结构模型的协议[HTTP不止有一问一答(访问网站)结构模型,还有多问一答(上传文件),一问多答(下载文件).多问多答(远程桌面)结构模型]。

HTTP协议抓包工具----Fiddler

HTTP的请求和相应的格式是有所差异的。那如何查看到HTTP的请求和响应的格式呢?这里就需要用到HTTP抓包工具----Fiddler。

抓包工具的原理

Fiddler相当于是一个"代理"。

浏览器访问 baidu.com 时, 就会把 HTTP 请求先发给 Fiddler, Fiddler 再把请求转发给baidu 的服务器. 当 baidu 服务器返回数据时, Fiddler 拿到返回数据, 再把数据交给浏览器. 因此 Fiddler 对于浏览器和 baidu 服务器之间交互的数据细节, 都是非常清楚的。

代理就可以简单理解为一个跑腿小弟. 比如说你想买罐冰阔落, 又不想自己下楼去超市, 那么就可以把钱给跑腿小弟, 跑腿小弟来到超市把钱给超市老板, 再把冰阔落拿回来交到你手上. 这个过程中, 这 个跑腿小弟对于 "你" 和 "超市老板" 之间的交易细节, 是非常清楚的.

 Fiddler的安装

Fiddler是用来专门抓HTTP的抓包工具,使用起来简单方便, 下载地址:https://www.telerik.com/fiddler/

选择经典版就可以了,下载后安装过程比较简单,一路next就好了。安装好了之后,打开Fiddler就是这样的页面。

新安装的fiddler需要手动开启HTTPS功能,并且安装证书,否则只能抓HTTP。可能有小伙伴疑惑为什么非要开启HTTPS,因为当前的互联网环境是以HTTPS为主,纯HTTP已经很少见了,如果不开启的话们只能抓到很少的HTTP。那如何开启HTTPS功能并安装证书呢?很简单,找到工具栏中的Tools选择Options...

再选择HTTPS,把小方框都勾上,再点击OK。点击OK后 ,会弹出一个窗口询问你是否要安装根证书(英文描述的),此时一定要选择"同意(Yes)",否则就只能"喜提"重装fiddler了。

Fiddler的使用

  • 左侧窗口显示了所有的 HTTP(HTTPS)请求/响应, 可以选中某个请求查看详情;
  • 右侧上方显示了 HTTP 请求的报文内容 (切换到 Raw 标签页可以看到详细的数据格式);
  • 右侧下方显示了 HTTP 响应的报文内容(切换到 Raw 标签页可以看到详细的数据格式);
  • 请求和响应的详细数据, 可以通过右下角的 View in Notepad 通过记事本打开;
  • 可以使用 ctrl + a 全选左侧的抓包结果, delete 键清除所有被选中的结果.

除了fiddler之外,加速器,vpn等程序也是代理的,而代理程序之间可能会发生冲突。如果你的电脑使用fiddler时不能抓包,就需要检查是否关闭之前的代理软件(也可能是浏览器插件),还可以尝试使用不同的浏览器.edge浏览器有的时候就不行。使用fiddler的时候一定要打开浏览器,这样才会抓到包!

左侧窗口抓到的HTTP/HTTPS还有几种颜色,不同颜色的包是有区别的。

TCP,UDP,IP协议等都是二进制格式的协议,而HTTP协议是文本格式的协议(协议里的内容都是字符串)。HTTP响应也是文本的,但是直接查看往往看到的是二进制数据,这是因为响应数据被压缩了。HTTP响应经常被压缩,因为压缩之后,体积会变小,传输的时候就节省网络带宽的消耗。

解压缩之后,可以看到响应的数据其实是html。浏览器上显示的网页就是html,往往都是浏览器先请求对应的服务器,从服务器这边拿到的网页数据(html)。

HTTP请求(Request)

认识URL

URL基本格式

平时我们俗称的 "网址" 其实就是说的 URL (Uniform Resource Locator 统一资源定位符). 互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它. URL 的详细规则由因特网标准RFC1738 进行了约定. ( https://datatracker.ietf.org/doc/html/rfc1738)

关于URL Encode

像 / ? : 这样的字符,已经被url当作特殊意义理解了,因此这些字符不能随意出现。如果某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义。

转义的规则:将需要转义的字符转为16进制,然后从右到左,取4位(不足4位直接处理),每2位做1位,前面加上%,编码成%XY的格式。例如:

"+"被转义了"%2B"。urlencode本质上就是一种"转移字符",中文,汉字都需要转义。所以在使用url的时候,要记得针对query string的内容进行urlencode工作;如果处理不好,有些浏览器就可能会解析失败,导致请求无法正常进行。

urlencode查询工具

认识"方法"(method)

方法说明支持的HTTP协议版本
GET获取资源

1.0、1.1

POST传输实体主体1.0、1.1
PUT传输文件1.0、1.1

HEAD

获取报文首部1.0、1.1
DELETE删除文件1.0、1.1
OPTIONS询问支持的方法1.1
TRACE追踪路径1.1
CONNECT要求用隧道协议连接代理1.1
LINK建立和资源之间的联系1.0
UNLINE断开连接关系1.0

1.GET方法

GET是最常用的HTTP方法,常用于获取服务器的上的某个资源。在浏览器中直接输入URL,此时浏览器就会发送出一个GET请求;另外,HTML中的link,img,script等标签也会触发GET请求。

使用Fiddler观察GET请求

打开FIddler,访问百度主页,观察抓包结果

在上面的结果中可以看到:

最上面的是通过浏览器地址栏发送的GET请求,

下面的和baidu域名相关的请求,有些是通过html中的link/script/img标签产生的,例如:

选中第一条观察详细请求结果

GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://baidu.lianghi.com/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: BIDUPSID=79F813F246038BE54094317A1201810A; PSTM=1646541110; sug=3; sugstore=0; ORIGIN=0; bdime=0; BAIDUID=7C2E90E71943EB65815B8439683C3DDE:FG=1; MCITY=-132%3A; BD_UPN=12314753; H_WISE_SIDS=40079_40303_40381_40367_40416_40466_40513_40398_40446_60044_60026_60048_40510; H_WISE_SIDS_BFESS=40079_40303_40381_40367_40416_40466_40513_40398_40446_60044_60026_60048_40510; H_PS_PSSID=40303_40381_40367_40416_40513_40398_40446_60044_60026_60048_40510; H_PS_645EC=4073MW%2FR8Rwj7zGcBEBGZvw5SrlssBbBY%2BCQob5J2GOeABi0ls3wGfgvn5nphyPuZ0f5tCTH7UmDag; delPer=0; BD_CK_SAM=1; PSINO=7; COOKIE_SESSION=4495423_12_8_8_9_47_1_4_4_8_0_5_314_777_0_0_1708435125_1707235834_1712930514%7C9%23953_168_1707235783%7C9; BAIDUID_BFESS=7C2E90E71943EB65815B8439683C3DDE:FG=1; BDRCVFR[ELcT9xRAHcn]=eeLTGPPn8OcUA-9UhICpi4WUvY; BA_HECTOR=a4a10h8h8k00002105alag8huupcpc1j1igj81t; ZFY=AjeyjQ2sO8VFcM33qq5gEB3DIPgQm2JtRU11NOSYSKw:C; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598

GET请求的特点

  • 首行第一部分为GET
  • URL的query string可以为空也可以不为空
  • header部分有若干个键值对结构
  • body部分为空

2.POST方法

POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面). 通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求.

使用 Fiddler 观察 POST 方法

在Gitee的登陆页面,输入用户名和密码,点击登录就可以看到POST请求:

点击这个请求查看详情:

POST https://gitee.com/login HTTP/1.1
Host: gitee.com
Connection: keep-alive
Content-Length: 451
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://gitee.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://gitee.com/login?redirect_to_url=%2F
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: user_locale=zh-CN; oschina_new_user=false; sensorsdata2015jssdkchannel=%7B%22prop%22%3A%7B%22_sa_channel_landing_url%22%3A%22%22%7D%7D; remote_way=http; slide_id=10; visit-gitee--2024-03-06=1; BEC=1f1759df3ccd099821dcf0da6feb0357; Hm_lvt_24f17767262929947cc3631f99bfd274=1711546573,1711803626,1712455685,1712905788; user_return_to_0=%2F; tz=Asia%2FShanghai; csrf_token=C3f70Gm%2FA%2BYSy6vVSAyQxCaDKxjnl38R18CnowRWZnFI2JRuu%2F89mgMdlWDDv6k9%2F%2FN%2FH9iHFDmv4WcH89%2BN7w%3D%3D; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2218ed2d273201ea-0554d2fb0371014-26031151-1327104-18ed2d273211a0d%22%2C%22first_id%22%3A%22%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%22185753f3df8af2-0501c17e118eecc-6b3e555b-1327104-185753f3df9ba3%22%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTg1NzU1YzJiOGJiNTYtMGI4MzAwYTFkMTM5ODU4LTZiM2U1NTViLTEzMjcxMDQtMTg1NzU1YzJiOGMxMjU5IiwiJGlkZW50aXR5X2xvZ2luX2lkIjoiMTIyOTI0NjEifQ%3D%3D%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2212292461%22%7D%7D; Hm_lpvt_24f17767262929947cc3631f99bfd274=1712933991; gitee-session-n=aENXeXRIeW1ncWVZUWY4bDFRQitMSjl3WHZiaGNKYTJoWVpsbS9RRkZQUkU4Uy81a2JlMGpuMkhwRlNLSDFWY0N1UDdLZEtNZ3FJd0hqK21EQ0M5NGxHQXptVUNhcG5xSmdZQ0lKNEgyMHZUbndsZU1RZzBTaW02Sk85M2Z4S0xHbnEzQVVmaFVEbE5yRmxQemdkRTRuOEQvS0JqS2phaGp3Q29FTkNPOCtxRTJ0aUVRMHRHaFo1U3RJQXphOHdUckF3RnJIVUs1S29McGlKQnllVnNoOWxEQ2IrVkZkbDlYcHdrdjRSV1cwSG4zZ2hUYXBzclkxN1ZMUVRjdHFYWkY1ZnMyOURNaUkzdVNHc2RQMG1ESStlU1ArUjd5UFZqNU5Da2lUUWhqNDFoYmFQM05VS2h1RVB6anZOSGJodWZUQWNjWWJ2Wk1Cb3kzZEl0dklNeEI4TmtlcFc1bDZUU0J5aGZVd3U4eUdsMldMQ2pqbittSURiNmVCN0x1bHI3MlFBc1RnN1o2bHdnbG9La0liRVV5Q2FIdHFpWmkvWHN0aWVlSTZyZ1FsUU9aajZkL0FPb0lIZUlhTkwrUEt0OU1qQWwzVHRUQ0doZ3hpSld3SGVnL3J2WGl0YmpMZFgyY0hVZXNwbDZlMm1sYmsvdmFYbG90cDlNc2R1c3dMQmFzWXp5YmExL2d6bWxpL0E5ekxmVk84bmF4b0NYQzQzUHd6ZnorT3ZqZEZ3PS0tdjMrRUp3NDFiVVJTcmhSQ25ZbjdVUT09--9c96a252f9e0eaec9a3d74575763c3bc0377173c

encrypt_key=password&utf8=%E2%9C%93&authenticity_token=qW1TX2jod3XXr7MRMb5d08GHRvxk1wLEd41U%2BmXxbyTqwjzhuqhJCcZ5jaS6DWQqGPcS%2B1vHaewPrJRekniEug%3D%3D&redirect_to_url=%2F&user%5Blogin%5D=13594515074&encrypt_data%5Buser%5Bpassword%5D%5D=rzTAwGtEBttIPjf1aTEANoKi0hGKi0f%2FvP9dTwh5Oef4dhhumybuG%2FY04kTknnwRZ4WML3F1ZiJNpg5JB0z%2FmVW0bnuoP6nJeWgXONE5QIh%2F5y9Y1Y%2FhwWXteoDVDsZ%2BqYFij%2FdHrtcR8LnUHYRTjsdd4IOU34Z2kLuo1E%2Bwqao%3D&user%5Bremember_me%5D=0

POST请求的特点

  • 首行的第一部分为POST
  • URL的query string一般为空(也可以不为空)
  • header部分有若干个键值对结构
  • body部分一般不为空,boby内的数据格式通过header的Content_Type的指定,body的长度有header的Content-Length指定。

GET和POST的区别(经典面试题)

其实GET和POST没有本质上的区别(双方可以替换对方的场景),但是在使用习惯上还是有差别的:

1.语义上的差异:GET一般用来获取数据,POST一般用来提交数据

2.GET经常把传递给服务器的数据放在query string中,POST则是经常放到body中.(上述情况并不是绝对的,GET也可以使用body,POST也可以使用query string,但使用的前提是客户端服务器都得按照一样的方式来处理代码)

3.其他方法

  • PUT和POST相似,一般用于更新
  • DELETE删除服务器指定资源
  • OPTIONS返回服务器所支持的请求方法
  • HEAD类似于GET,只不过响应体不返回,只返回响应头
  • TRACE回显服务器段收到的请求,测试的时候会用到
  • CONCECT预留,暂无使用
     

认识请求头"报头"(header)

header的整体格式也是键值对结构,每个键值对独占一行.建和值之间只用分号分割。

报头的种类有很多,这里介绍几个常见的:

1.HOST

表示服务器主机的地址和端口

2.Content-Length

表示body中的数据长度

3.Content-Type

表示请求的body中的数据格式,body中的格式可选择的方式是很多的:

请求:1) json;  2) form表单的格式 ;  3) form-data的格式

响应:1) html;   2) css;   3) js;   4) json;   5) 图片....

:请求里有body才会有Content-Length和Content-Type这两个属性,通常情况下,GET请求没有body,POST请求有body。

之前说过TCP数据包在传输时会涉及到粘包问题,而HTTP在传输层就是基于TCP的。如果使用同一个TCP连接,传输多个HTTP数据包,此时就会使多个HTTP数据包粘在一起,所以接收方解析的时候,就需要能够清楚知道HTTP数据包之间的边界。

对于GET这种没有body的请求,直接用使用空行(分隔符)来区分边界;对于POST这种有body的请求,就结合空行和Content-Length来进行区分。

4.User-Agent(简称UA)

描述了使用什么设备上网。UA以前是用来区分浏览器的,但现在浏览器之间的差异已经很小了,UA的作用也没那么关键了。现在的UA主要用来区分是PC端还是移动端。

5.Referer

描述当前这个页面是从哪个页面跳转过来的。

如果直接在浏览器中输入url,或者直接通过收藏夹访问页面时是没有Referer的。

6.Cookie

Cookie可以认为是浏览器在被本地存储数据的一种机制。

浏览器的数据来自于服务器,浏览器的后续操作也是要交给服务器的,可以说,服务器管理了一个网站的各种核心数据。但是程序运行过程中,也会有一些数据是需要在浏览器这边存储的,并且在后续的请求的时候数据可能需要再发给服务器。比如上次登录的时间,上次访问的时间,用户的身份信息等这种临时性的数据,存储在浏览器中是比较合适的。

这样更容易想到的是把数据直接存储在本地文件中,但实际上是不可行的,如果访问的网站里有病毒,直接入侵你的硬盘,带来的后果是很严重的,所以浏览器为了安全性,禁止网页直接访问电脑的文件系统。为了保证安全性,又能进行存储数据,于是就引入了Cookie。Cookie也是按照硬盘文件的方式保存的,但是浏览器那操作文件给封装了,网页只能王Cookie中存储键值对(键值对中是简单的字串)。

Cookie往往存储的是从服务器返回的数据(也可以是页面自己生成的),Cookie存储到浏览器主机所在的硬盘上,并且按照域名为维度来存储。每个不同的域名下都可以有不同的Cookie,不同网站之间的Cookie并不冲突。

Cookie是按照键值对的形式来存储的,这些键值对也是程序员自定义的(和query string差不多)。键值对之间使用 ; 分割,键和值之间使用 = 分割。后续在请求服务器的时候,就会把Cookie中的内容自动带入到请求中,服务器通过Cookie的内容做一些逻辑上的处理就可以了。

请求格式

1)首行

HTTP请求的第一行有三个部分信息,三个部分使用空格分隔

(1)GET HTTP请求的"方法"(method)

(2)URL 唯一资源定位符,描述了一个资源在网络中的位置 

(3)版本号  可以看到www.baidu.com网站使用的是HTTP/1.1

2)请求头(header)

请求头记录的是键值对结构的数据(不止一个键值对),这里的键值对都是属于"标准规定"的,每个键值对都是独占一行的,建和值之间使用 :空格 来区分。

3)空行

请求头的结束标记。

4)正文(body)

body不是每个HTTP请求都有的,有的HTTP请求有,有的没有。

HTTP响应(response)

认识"状态码"(statu code)

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599):

这里只介绍几个常见的状态码:

1.200 OK

这是一个最常见的状态码,表示访问成功。抓包抓到的大部分结果都是200

2.404 Not Found

表示没有找到资源。在浏览器中输入一个URL,目的就是为了访问服务器上的一个资源,如果这个URL标识的资源不存在,那么就会出现404这样的响应。

3.403 Forbidden

表示访问被拒绝。有的页面通常需要用户具有一定的权限才能访问(登陆后才能访问). 如果用户没有登陆直接访问, 就容易见到 403。

4.405 Method Not Allowed

前面我们已经学习了 HTTP 中所支持的方法, 有 GET, POST, PUT, DELETE 等. 但是对方的服务器不一定都支持所有的方法(或者不允许用户使用一些其他的方法).

5.500 Internal Server Error

服务器出现内部错误. 一般是服务器的代码执行过程中遇到了一些特殊情况(服务器异常崩溃)会产生这个 状态码.

6.504 Gateway Timeout

当服务器负载比较大的时候, 服务器处理单条请求的时候消耗的时间就会很长, 就可能会导致出现超时的情况。

7.301 Moved Permanently

永久重定向,当浏览器收到这种响应时, 后续的请求都会被自动改成新的地址。响应报文的 header 部分会包含一个 Location 字段, 表示要跳转到哪个页面.

理解重定向:请求中访问的是A这样的地址,响应返回了一个重定向报文,告诉你应该要访问B地址。

很多时候,页面跳转就可以通过重定向来实现,还有的时候,某个网站的服务器迁移了(IP/域名变了)就可以给旧的地址挂一个重定向响应,访问旧地址的用户就会自动跳转到新的地址。\

8.302 Move temporarily

临时重定向,在登陆页面中经常会见到 302. 用于实现登陆成功后自动跳转到主页。也通过 Location 字段来表示要重定向到的新地址。

状态码小结

认识响应"报头"(header)

响应报头的基本格式和请求报头的格式基本一致.。类似于 Content-Type, Content-Length 等属性的含义也和请求中的含义一致。

响应格式

1)首行

HTTP响应的第一行也有三个部分信息,三个部分使用空格分隔

(1)版本号  HTTP/1.1

(2)状态码 (200) 描述了请求的结果

(3)状态码描述(OK) OK就是表示成功了

2)响应头(header)

响应头也是键值对结构(不止一个键值对),这里的键值对都是属于"标准规定"的,每个键值对都是独占一行的,建和值之间使用 :空格 来区分。

3)空行

响应头的结束标记。

4)正文(body)

响应正文里的内容可能会比较长,可以是多种格式,比如HTML,CSS,JS,JSON,XML,图片,音频,视频等等。

这次的文章就分享到这里了,有问题小伙伴可以留言评论,我们一起共勉

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值