NodeJS

本文详细介绍了NodeJS中的HTTP操作,包括HTTP状态码、请求方式,特别讲解了GET和POST数据的处理,以及文件数据的处理。还涵盖了fs模块、模块系统、package.json的使用、系统包如assert、path、url、querystring和net等。接着讨论了数据交互,如原生AJAX、fetch、JSONP、FormData和WebSocket,特别提到了socket.io的使用。最后,简述了NodeJS操作数据库、流操作和启动器的相关内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. http

1.1 http状态码

分类描述
1**信息
2**成功
3**重定向
4**客户端错误
5**服务器错误

1.2 请求方式

  • GET 获取

    • 数据放在 url 里面传输的,容量 ≤ 32k
  • POST 发送数据

    • 容量大

2. 接收 GET 数据

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<form action="http://localhost:8080/aaa" method="GET">
			用户:<input type="text" name="username">
			密码:<input type="password" name="password">
			<input type="submit" id="" name="" value="提交"/>
		</form>
	</body>
</html>
const http = require('http');
const url = require('url');

let server = http.createServer((req, res) => {
	// 解析 GET 过来的数据
	// 添加参数 true,能将query参数也一起解析了
	let result = url.parse(req.url, true);
	let {query, pathname} = result;
	console.log(result);
	console.log(query,pathname);

});


server.listen(8080);

在这里插入图片描述

3. 原生处理 POST 数据

3.1 普通数据 —— querystring,url

const http = require('http');
const querystring = require('querystring');

let server = http.createServer((req, res) => {
    console.log(req.method); // POST
    let arr = [];
    // 当有数据
    req.on('data',(buffer) => {
        // console.log(buffer); // <Buffer 75 73 65 72 6e 61 6d 65 3d 61 64 6d 69 6e 26 70 61 73 73 77 6f 72 64 3d 31 32 33 33 32 31>
        arr.push(buffer);
    });

    // 数据结束
    req.on('end',() => {
        let buffer = Buffer.concat(arr);
        let post = querystring.parse(buffer.toString());
        console.log(post);
        // console.log(buffer.toString()); // <Buffer 75 73 65 72 6e 61 6d 65 3d 61 64 6d 69 6e 26 70 61 73 73 77 6f 72 64 3d 31 32 33 33 32 31>
    });
});


server.listen(8080);

在这里插入图片描述

3.2 文件数据 buffer

  • form上传文件,要添加 enctype='application/x-www-form-urlencoded',enctype 默认值为 application/x-www-form-urlencoded

     <form action="http://localhost:8080/upload" method="POST" enctype="multipart/form-data">
            用户: <input type="text" name="username"><br>
            密码: <input type="password" name="password"><br>
            <input type="file" name="f1"><br><br>
            <input type="submit">
    </form>
    
    const http = require('http');
    
    
    http.createServer((req, res) => {
        let  arr = [];
        console.log(req.headers);
        req.on('data',(buffer) => {
            arr.push(buffer);
        });
        req.on('end',() => {
            let buffer = Buffer.concat(arr);
    
            console.log(buffer.toString());
        });
    }).listen(8080);
    

    在这里插入图片描述

    结果:
    在这里插入图片描述
    注:在请求头中能获取到分隔符,注意横杠数

  • 在 buffer 中查找

    let buffer = new Buffer('abc\r\ndfadsa\r\ndfawfdsafdsa');
    
    console.log(buffer.indexOf('\r\n')); // 3
    
  • 切分方法封装

    let buffer = new Buffer('abc\r\ndfadsa\r\ndfawfdsafdsa');
    
    console.log(buffer.indexOf('\r\n')); // 3
    
    function bufferSplit(buffer, delimiter) {
        let arr = [];
        let n = 0;
    
        while ((n = buffer.indexOf(delimiter)) != -1) {
            arr.push(buffer.slice(0, n));
    
            buffer = buffer.slice(n + delimiter.length); //跳过分隔符长度
        }
        arr.push(buffer); // 将最后的一块添加进去
    
        return arr;
    };
    
    console.log(bufferSplit(buffer, '\r\n').map(a => a.toString()));
    

    在这里插入图片描述

  • 源码

    const http = require('http');
    const fs = require('fs');
    
    
    function bufferSplit(buffer, delimiter) {
        let arr = [];
        let n = 0;
    
        while ((n = buffer.indexOf(delimiter)) != -1) {
            arr.push(buffer.slice(0, n));
    
            buffer = buffer.slice(n + delimiter.length); //跳过分隔符长度
        }
        arr.push(buffer); // 将最后的一块添加进去
    
        return arr;
    };
    
    http.createServer((req, res) => {
        let arr = [];
        let boundary = '--' + req.headers['content-type'].split('; ')[1].split('=')[1]
    
        req.on('data', (buffer) => {
            arr.push(buffer);
        });
        req.on('end', () => {
            let buffer = Buffer.concat(arr);
    
            // 按照分隔符切分
            let result = bufferSplit(buffer, boundary);
    
            // 去掉头 null 和 尾 \r\n--
            result.pop();
            result.shift();
    
            // 针对其中的每一个处理
            result.forEach(buffer => {
                // 去掉 头尾的 \r\n
                buffer = buffer.slice(2, buffer.length - 2);
    
                // 使用 \r\n 切
                let n = buffer.indexOf('\r\n\r\n');
    
                let info = buffer.slice(0, n).toString();
                let data = buffer.slice(n + 4);
    
                // console.log(info.toString());
    
                if (info.indexOf('\r\n') != -1) {
                    // 文件
                    let result2 = info.split('\r\n')[0].split('; ');
                    let name = result2[1].split('=')[1];
                    let filename = result2[2].split('=')[1];
    
                    // 去除引号
                    name = name.substring(1, name.length - 1);
                    filename = filename.substring(1, filename.length - 1);
    
    
                    // 将内容写入
                    fs.writeFile(`upload/${filename}`, data, err => {
                        if(err){
                            console.log(err);
                        }else{
                            console.log('上传成功');
                        }
                    });
    
                } else {
                    // 普通信息
                    // 截取 info 中的 name 值
                    let name = info.split('; ')[1].split('=')[1];
                    name = name.substring(1, name.length - 1);
    
                    // console.log(name, data.toString());
                }
            })
        });
    }).listen(8080);
    

    在这里插入图片描述
    —— 7.6 multiparty

4. fs

const fs = require('fs');

fs.writeFile('./a.txt', 'abc', err => {
	if (err) {
		console.log("失败",err)
	} else {
		console.log("成功")
	}
});

fs.readFile('./a.txt', (err, data) => {
	if (err) {
		console.log("错误", err);
	} else {
		console.log("成功", data.toString());
	}
})

5. 模块系统

  • require

    • 如果带有路径 —— 去路径下找
    • 如果没有:
      • node_modules文件夹找
      • 如果没有,再去系统 node_modules去找
  • exports

    exports.a = 12;
    exports.b = 5;
    
  • module 批量导出

    module.exports = {
        a: 12,
        b: 6
    }
    
    module.exports = function () {
        return 1;
    }
    
    module.exports = class {
        c(name) {
            this.name = name;
        }
        show() {
            return this.name;
        }
    }
    

6. package.json

  • 使用 npm init 初始化项目, 会生成一个 package.json 的文件
    在这里插入图片描述
  • 有了package.json文件,直接使用 npm install 命令,就会在当前目录中安装所需要的模块
  • npm install xxx --save / npm i xxx -S 表示将该模块写入dependencies属性
    在这里插入图片描述
  • npm install xxx --save-dev / npm i xxx -D 表示将该模块写入devDependencies属性
    在这里插入图片描述
  • 同时省略则表示不写入package.json文件中。

7. 系统包

7.1 assert 断言

const assert = require('assert');

// assert(条件,消息);

assert(5 > 3, 'aaa');

// 深度比较
// assert.deepEqual(变量, 预期值, 消息);
// assert.deepStrictEqual(变量, 预期值, 消息); // ===

7.2 path 路径

const path = require('path');

let str = '/root/f/1.jpg';
console.log(path.dirname(str)); // /root/f
console.log(path.extname(str)); //.jpg
console.log(path.basename(str)); // 1.jpg
console.log(path.resolve(str)); // E:\root\f\1.jpg
console.log(path.resolve(str, '../a')); // E:\root\f\a
console.log(path.resolve(str, '../a', './b')) // E:\root\f\a\b
console.log(__dirname); //指向被执行 js 文件的绝对路径

7.3 url

const url = require('url');

let str1 = 'http://www.bing.com/a/b/1.html?c=12&d=20';
console.log(url.parse(str1),true);

在这里插入图片描述

7.4 querystring 请求数据

const querystring = require('querystring');

console.log(querystring.parse('a=12&b=22&c=34')); // { a: '12', b: '22', c: '34' }
console.log(querystring.stringify({
    a: '12',
    b: '22',
    c: '34'
})); //a=12&b=22&c=34

7.5 net 网络通信

  • Node.js Net 模块提供了一些用于底层的网络通信的小工具,包含了创建服务器/客户端的方法。

7.6 multiparty

const http = require('http');
const multiparty = require('multiparty');

http.createServer((req, res) => {
    let form = new multiparty.Form({
        uploadDir: './upload'
    });

    form.parse(req);

    form.on('field', (name, value) => {
        console.log('字段', name, value);
    });

    form.on('file', (name, file) => {
        console.log('文件', name, file);
    });

    form.on('close', () => {
        console.log('表单解析完成');
    });
}).listen(8080);

在这里插入图片描述

8. 数据交互

8.1 原生ajax、跨域

  • 服务器
    const http = require('http');
    
    // 允许访问的域名
    let allowOrigin = {
        'http://localhsot': true,
        'http://127.0.0.1:5500': true
    }
    
    http.createServer((req, res) => {
        console.log(req.headers);
    
        let {
            origin
        } = req.headers;
        
        if (allowOrigin[origin]) {
            // 允许跨域
            res.setHeader('Access-Control-Allow-Origin', '*')
        }
    
        res.write('{"a":123}');
        res.end();
    }).listen(8080);
    
  • 原生 ajax
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>ajax请求</title>
    </head>
    
    <body>
        <input type="button" value="请求" id="btn1">
    </body>
    <script>
        window.onload = function () {
            let oBtn = document.getElementById('btn1');
    
            oBtn.onclick = function () {
                let ajax = new XMLHttpRequest();
    
                ajax.open('GET', 'http://localhost:8080', true);
    
                ajax.send();
    
                ajax.onreadystatechange = function () {
                    if (ajax.readyState == 4) {
                        if (ajax.status >= 200 && ajax.status < 300 || ajax.status == 304) {
                            console.log('成功');
                            let rel = JSON.parse(ajax.responseText)
                            console.log(rel);
                        } else {
                            alert('失败');
                        }
                    }
                };
            };
        }
    </script>
    
    </html>
    
    在这里插入图片描述

8.2 fetch – 原生

  • txt

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script>
            window.onload = function () { 
                let oBtn = document.getElementById('btn1');
    
                oBtn.onclick =async function () { 
                    // 请求数据
                    let res =await fetch('www/aaa.txt');
    
                    // 解析文本数据
                    console.log(res);
                    let str =await res.text();
                    console.log(str);
                 };
             };
        </script>
    </head>
    
    <body>
        <input type="button" value="读取" id="btn1">
    </body>
    
    </html>
    

    在这里插入图片描述

  • json

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script>
            window.onload = function () { 
                let oBtn = document.getElementById('btn1');
    
                oBtn.onclick =async function () { 
                    // 请求数据
                    let res =await fetch('www/13.json');
    
                    // 解析json数据
                    console.log(res);
                    let json =await res.json();
                    console.log(json);
                 };
             };
        </script>
    </head>
    
    <body>
        <input type="button" value="读取" id="btn1">
    </body>
    
    </html>
    

    在这里插入图片描述

  • blob

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>fetch解析二进制数据</title>
        <script>
            window.onload = function () {
                let oBtn = document.getElementById('btn1');
                let oImg = document.getElementById('img1');
    
                oBtn.onclick = async function () {
                    // 请求数据
                    let res = await fetch('www/1.jpg');
    
                    // 解析
                    let data = await res.blob();
                    console.log(data);
    
                    let url = URL.createObjectURL(data);
                    oImg.src = url;
                };
            };
        </script>
    </head>
    
    <body>
        <input type="button" value="读取" id="btn1">
        <img src="" id="img1" alt="">
    </body>
    
    </html>
    

    在这里插入图片描述

8.3 jsonp

  • Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

  • 原生

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <title>jsonp</title>
        <script>
            function show(s) {
                console.log(s);
            };
    
            window.onload = function () {
                let oTxt = document.getElementById('txt1');
                oTxt.oninput = function () {
                    let url =
                        `https://www.baidu.com/sugrec?prod=pc&wd=${this.value}&req=2&csor=2&cb=show`;
                    let oS = document.createElement('script');
                    oS.src = url;
    
                    document.head.appendChild(oS);
                }
            };
        </script>
    </head>
    
    <body>
        <input type="text" id="txt1">
    </body>
    
    </html>
    

    在这里插入图片描述

  • jQuery - jsonp

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script src="../public_js/jquery.min.js"></script>
        <script>
            $(function () {
                $('#txt1').on('input', function () {
                    $.ajax({
                        url: `https://www.baidu.com/sugrec?prod=pc`,
                        data: {
                            wd: $(this).val()
                        },
                        dataType: "jsonp",
                        jsonp: "cb",
                    }).then(function (s) {
                        console.log(s);
                    }, err => {
                        console.log("失败");
                    });
                })
            })
        </script>
    </head>
    
    <body>
        <input type="text" id="txt1">
    </body>
    
    </html>
    

    在这里插入图片描述

8.4 FormData – ajax2.0

  • 服务器

    const http = require('http');
    const multiparty = require('multiparty');
    
    http.createServer((req, res) => {
        let form = new multiparty.Form({
            uploadDir: './upload/'
        });
    
        form.parse(req);
    
        form.on('field', (name, value) => {
            console.log('field', name, value);
        });
    
        form.on('file', (name, file) => {
            console.log('file', name, file);
        });
    
        form.on('close', () => {
            console.log("解析完成");
        });
    }).listen(8080);
    
  • 原生提交 FormData

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
    </head>
    
    <body>
        <form action="http://localhost:8080" id="form1" method="POST">
            用户:<input type="text" name="user"> <br>
            密码:<input type="password" name="pass"> <br>
            <input type="file" name="f1">
            <input type="submit" value="提交">
            <span></span>
        </form>
    </body>
    <script>
        let oForm = document.getElementById('form1');
        console.log(oForm);
    
        // 
        oForm.onsubmit = function () {
            let formdata = new FormData(oForm);
    
            let xhr = new XMLHttpRequest();
    
            xhr.open(oForm.method, oForm.action, true);
            xhr.send(formdata);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) {
                        alert('成功');
                    } else {
                        alert('失败');
                    }
                }
            };
            return false;
        }
    </script>
    
    </html>
    

    在这里插入图片描述

  • jquery 提交 FormData

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script src="../public_js/jquery.min.js"></script>
    </head>
    
    <body>
        <form action="http://localhost:8080" id="form1" method="POST">
            用户:<input type="text" name="user"> <br>
            密码:<input type="password" name="pass"> <br>
            <input type="file" name="f1">
            <input type="submit" value="提交">
            <span></span>
        </form>
    </body>
    <script>
        $(function () {
            $('#form1').on('submit', function () {
                let formdata = new FormData(this);
    
                $.ajax({
                    type: this.method,
                    url: this.action,
                    data: formdata,
                    processData: false,
                    contentType: false
    
                }).then(res => {
                    console.log(res);
                }, err => {
                    console.log(err);
                });
    
                return false;
            })
        });
    </script>
    
    </html>
    

    注意配置 processDatacontentType

  • 构建form

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script src="../public_js/jquery.min.js"></script>
    </head>
    
    <body>
        <div id="d1">
            用户:<input type="text" id="user"> <br>
            密码:<input type="password" id="pass"> <br>
            <input type="file" id="f1">
            <input type="button" id="btn1" value="提交">
            <span></span>
        </div>
    </body>
    <script>
        window.onload = function () {
            let oBtn = document.getElementById('btn1');
            oBtn.onclick = function () {
                let formdata = new FormData();
    
                formdata.append('username', document.getElementById('user').value);
                formdata.append('password', document.getElementById('pass').value);
                formdata.append('f1', document.getElementById('f1').files[0]);
                console.log(formdata);
    
                let xhr = new XMLHttpRequest();
    
                xhr.open('post', 'http://localhost:8080', true);
                xhr.send(formdata);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4) {
                        if (xhr.status == 200) {
                            alert('成功');
                        } else {
                            alert('失败');
                        }
                    }
                };
            };
    
        };
    </script>
    
    </html>
    

    使用 append 方法追加数据

8.5 WebSocket

  • 性能好

  • 双向

  • 握手加密秘钥 258EAFA5-E914-47DA-95CA-C5AB0DC85B11

  • 原生连接 websocket

    const net = require('net');
    const crypto = require('crypto');
    
    function parseHeader(str) {
        // 切分 并且过滤空行
        let arr = str.split('\r\n').filter(line => line);
        // 忽略第一行
        arr.shift();
    
        let headers = {}
        arr.forEach(function (line) {
            let [name, value] = line.split(':');
    
            // 取出行首 行尾的空格 并且全小写
            name = name.replace(/^\s+|\s+$/g, '').toLowerCase();
            value = value.replace(/^\s+|\s+$/g, '');
    
            headers[name] = value;
        });
        return headers;
    }
    
    let server = net.createServer(sock => {
        console.log('有人连接');
        sock.once('data', buffer => {
            let str = buffer.toString();
            let headers = parseHeader(str);
    
            // console.log(headers);
            // 判断是不是要协议升级
            if (headers['upgrade'] != 'websocket') {
                console.log('no upgrade');
                // 关闭 socket
                sock.end();
            }
            // 判断版本
            else if (headers['sec-websocket-version'] != '13') {
                console.log('no 13');
                sock.end();
            } else {
                // 验证 key -> 请求头有
                // 握手秘钥  258EAFA5-E914-47DA-95CA-C5AB0DC85B11
    
                let key = headers['sec-websocket-key'];
                let uuid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
                let hash = crypto.createHash('sha1');
    
                hash.update(key + uuid);
                let key2 = hash.digest('base64');
    
                sock.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade:websocket\r\n
                Connection:upgrade\r\nSec-Websocket-Accept:${key2}\r\n\r\n`);
            }
        })
    
        sock.on('end', function () {
            console.log('已断开');
        })
    });
    
    server.listen(8080);
    
  • 客户端

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <script>
            let ws = new WebSocket('ws://localhost:8080/');
    
            // 打开连接
            ws.onopen = function () {
                alert('连接已建立');
            };
            // 接收到消息
            ws.onmessage = function () {};
            // 正常关闭连接
            ws.onclose = function () {};
            // 错误
            ws.onerror = function () {};
        </script>
    </head>
    
    <body>
    
    </body>
    
    </html>
    
  • 结果
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

socket.io
  • 简单、方便
  • 兼容性好 —— IE5
  • 自动数据解析
  • 安装 socket.io
    在这里插入图片描述
  • 服务器
    // 建立普通 http
    const server = require('http').createServer();
    // 建立 ws
    const io = require('socket.io')(server, {
        cors: true
    });
    // 建立连接
    io.on('connection', sock => {
        
        // 接收客户端发送的数据
        sock.on('aaa', function (a, b) {
            console.log(a, b, a + b);
        })
    
        // 发送数据到 客户端
        let i = 0;
        setInterval(function () {
            i++;
            sock.emit('aaa', i)
        }, 1000);
    });
    server.listen(8080);
    
  • 客户端
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
    
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="http://127.0.0.1:8080/socket.io/socket.io.js" charset="utf-8"></script>
        <script>
            let socket = io.connect('ws://127.0.0.1:8080/');
    
            // 发送数据到客户端
            socket.emit('aaa', 12, 5);
    
            // 接收服务器发送过来的数据
            socket.on('aaa', function (a) {
                console.log(a);
            })
        </script>
    </head>
    
    <body>
    
    </body>
    
    </html>
    
    需要先引入 socket.js
  • 结果
    在这里插入图片描述
    在这里插入图片描述

9. NodeJS操作数据库

const http = require('http');
const mysql = require('mysql');

// 1.   连接服务器
let db = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'root',
    database: 'test'
});

// 执行 sql 语句
db.query('select * from clazz', function (err, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
    }
});

10. 流操作

const fs = require('fs');

// 读取流
let rs = fs.createReadStream('1.txt');

// 写入流
let ws = fs.WriteStream('2.txt');

// 管道
rs.pipe(ws);

rs.on('error', err => {
    console.log(err);
});

ws.on('finish', () => {
    console.log('写入成功');
})

在这里插入图片描述

  • 压缩
    const fs = require('fs');
    const zlib = require('zlib');
    
    let rs = fs.createReadStream('1.txt');
    let gz = zlib.createGzip();
    
    let ws = fs.WriteStream('2.txt.gz');
    
    // 读写流
    rs.pipe(gz).pipe(ws);
    
    rs.on('error', err => {
        console.log(err);
    });
    
    ws.on('finish', () => {
        console.log('写入成功');
    })
    
    在这里插入图片描述
  • 压缩 gzip 配合 http 使用 – 要设置请求头 content-encoding:gzip
    const http = require('http');
    const fs = require('fs');
    const url = require('url');
    const zlib = require('zlib');
    
    http.createServer(function (req, res) {
        let {
            pathname
        } = url.parse(req.url, true);
        let filename = './' + pathname;
    
        // 检查文件是否存在
        fs.stat(filename, function (err, stat) {
            console.log(err);
            if (err) {
                // 设置状态码
                res.writeHeader(404);
                res.write('not found');
                res.end();
            } else {
                // 创建读取流
                let rs = fs.createReadStream(filename);
                // 避免出错 服务器崩了
                rs.on('err', err => {});
    
                // 设置请求头
                res.setHeader('content-encoding', 'gzip');
                let gz = zlib.createGzip();
    
                // 压缩过后的数据 发送到客户端
                rs.pipe(gz).pipe(res);
            }
        })
    
    }).listen(8080);
    
    在这里插入图片描述

11. 启动器

  • 安装 cnpm i forever -g
  • 列表 forever list
  • 启动 forever xx.js 可用参数-l c:/a.log -e c:/err.log -a
  • 重启 forever restart xx.js
  • 停止 forever stop xx.js
  • 停止所有 forever stopall
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值