首页 / NODEJS / 近期学习node.js的总结
近期学习node.js的总结
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了近期学习node.js的总结,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含20936字,纯文字阅读大概需要30分钟。
内容图文
![近期学习node.js的总结](/upload/InfoBanner/zyjiaocheng/594/25fa0c83e9a749a3ade0accff6032b4c.jpg)
node.js总结
- 前言
- 一、什么是node.js
- 二、如果你已经安装好了npm和node,那就开始吧
- 总结
前言
要想学好node.js,首先要梳理好各个模块之间的关系,清楚各个模块的作用
1、bin文件夹:用于存放www.js,相当于加密形式,不让用户看到数据的操作,会禁止访问上一级目录
2、路由层:用于存放不同的路由,但是一次只会响应其中的一个
3、路由处理层:响应路由时要进行什么处理,比如数据增删改查,在这个层会得到处理
4、工具层:工具层与其他层都没有直接的联系,只有当要调用的时候才会被引入
一、什么是node.js
node.js是一个运行js代码的环境,与浏览器不同是。浏览器中的js由ECMAScript、DOM、BOM三部分组成,而node.js只有ECMAScript,但node.js运行在服务器端,这样就可以让前端工程师不止局限于页面操作,可以自己搭建服务器与数据库对接等.
二、如果你已经安装好了npm和node,那就开始吧
1、配置文件和开发环境
新建一个文件夹取名为“node_practice”,我们所有的node文件都将在这个文件夹中生成。
打开vscode,打开该文件夹,在根目录下新建一个叫app.js的文件,再新建一个bin文件夹,用于存放www.js。
打开bin目录下的www.js,输入以下代码
开启http服务
//http模块为node自带模块,可以直接引用
const http = require("http");
//severHandle模块是我们自己创建的,需要通过相对路径导入
const severHandle = require("../app.js")
//通过http开启服务,用3000端口去监听=>localhost:3000
http.createServer(severHandle).listen(3000);
接着我们在根目录下面的app.js这个文件中输入以下代码
app.js实际操作数据的模块
//定义了一个severHandle方法,将req请求头和res响应头传入,切记位置不能放反。
function severHandle(req, res) {
//req:请求头,里面包含了请求地址,请求参数等等。
//res:响应头,服务器中返回的数据
//在这里设置响应头的编码方式,不设置会出现乱码
res.setHeader("Content-type", "application/json");
//响应头输出语句
res.end("今天天气真好")
}
//通过module.exports将模块导出
module.exports = severHandle;
先安装插件nodemon,该插件可以实时去更新页面,不用手动更新
在根目录终端中输入npm install nodemon -D
-y为默认安装
-D为开发环境下安装
-S为当前项目环境,不管开发环境还是正式环境
-g为全局安装
等待安装完成后继续输入npm init -y
输入该指令可以使整个项目初始化
继续安装npm install mysql -s
该指令为我们后续连接数据库中使用,先提前安装
一系列安装后我们得到了三个新的文件,如图
我们打开其中package.json文件,找到其中的scripts部分
将其修改成
完成后我们打开终端,输入npm run dev指令
如无错误,即可正常运行起来
打开浏览器,输入localhost:3000地址,我们就可以看见我们输出的内容了。如图
2、设置请求头传来的参数
我们需要通过一些方法,将前端传输过来的参数进行保存,以便后续使用
所以我们将app.js代码部分更改成如下图所示
//querystring是node提供的方法,使用该方法可以将get请求中的参数保存在req.query中
const querystring = require("querystring")
//getBodyDate是我们自己写的获取除get请求以外其他请求带来的数据,需要通过外部导入
const getBodyDate = require("./src/utils/getBodyData")
async function severHandle(req, res) {
res.setHeader("Content-type", "application/json")
//如果请求方式是get,切记这里GET需要大写
if (req.method == "GET") {
//将req.url请求地址以“?”隔开,req.url.split("?")[1]部分为请求地址后面的参数。
//querystring.parse()将参数传入后将返回一个对象保存在req.query中。
req.query = querystring.parse(req.url.split("?")[1])
} else {
//如果为其他的请求方式将参数保存在req.body中
try {
//通过getBodyDate(req)方法获得的参数保存在req.body中,由于该方法是异步js,需要通过async,await等待其将参数传输完成,所以在severHandle方法前加上了async,让其等待getBodyDate(req)方法完成在继续执行后面的代码
req.body = await getBodyDate(req)
} catch (err) {
//捕捉错误
console.log(err);
}
}
//将req.url请求地址以“?”隔开,req.url.split("?")[0]部分为请求地址前面的路径
req.path = req.url.split("?")[0]
res.end("今天天气真好")
}
module.exports = severHandle;
接下来创建getBodyData的方法
在根目录下面新建src文件夹,在src中新建utils工具文件夹,用于存放getBodyDate这些工具类模块的地方。
打开getBodyDate.js在里面写上如下内容
//将请求头req作为参数传入
function getBodyDate(req) {
//异步js需要new一个Promise对象并返回
return new Promise((resolve, reject) => {
let str = ""
//数据传输开始,将参数chunk逐一保存在str字符串中
req.on("data", (chunk) => {
//chunk要通过toString()方法转成可识别字符串,不然是一堆机器语言。
str += chunk.toString();
});
//数据传输完成后得到一个包含全部参数的str字符串,使用JSON.parse(str)方法将其转换成对象,传给req.body保存起来
req.on("end", () => {
resolve(JSON.parse(str))
})
})
}
module.exports = getBodyDate;
通过上述操作,我们获得了基本的前端传来的信息,包括请求参数和地址,以对象的方式存在req中,如图所示
3、介绍该项目中用到的5个工具类模块
找到src文件夹中,新建utils文件夹,创建这5个不同的工具类模块
(1)getBodyData.js
作用:获取前端传来的参数,将其保存在req.body对象中
function getBodyDate(req) {
return new Promise((resolve, reject) => {
let str = ""
req.on("data", (chunk) => {
str += chunk.toString();
});
req.on("end", () => {
resolve(JSON.parse(str))
})
})
}
module.exports = getBodyDate;
该模块上述已讲过,不作过多描述
(2)checkData.js:参数检测模块
作用:用于检测参数格式是否正确,错误则会抛出响应错误信息。
该模块传入的参数1为req,参数2,3,4,5…为需要检测数据类型的名字
function testing(i, k) {
//这个str为单个错误记录,一次只会抛出一个错误
let str = ""
//通过判断传过来的参数i符合下列哪种类型,并且将符合类型的参数值进行正则判断
switch (i) {
case "phone":
if (!(/^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/.test(k))) {
str = "手机号错误";
}
break;
case "idcard":
if (!(/^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(k))) {
str = "id错误";
}
break;
case "date":
if (!(/^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$/.test(k))) {
str += "日期格式错误"
}
break;
case "startTime":
case "endTime":
if (!(/^(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$/.test(k))) {
str += "时间填写错误"
}
break;
case "dateId":
case "maxSize":
if (!(/^\d*$/.test(k))) {
str += "数字格式错误"
}
break;
default:
break;
}
return str;
}
//定义了一个checkData方法,参数1为req(请求头),参数2为(...arrData)为es6提供的方法,可以将后面传来的参数以此保存在arrData数组中
function checkData(req, ...arrData) {
//这个模块中的str用于记录全部参数的检查记录
let str = ""
let D = null;
if (req.method == "GET") {
D = req.query;
} else {
D = req.body;
}
arrData.forEach((item) => {
//遍历参数中的每项数据并将其传入testing中检测
str += testing(item, D[item]);
})
//遍历所有参数后抛出,如果没有错误,此时的str应该为空字符串
return str;
}
//导出checkData模块
module.exports = checkData;
此处省略一个arrData配图
(3)content.js:用于与mysql服务器创建连接
作用:开启与mysql的连接后,我们才可以对数据表中的数据进行操作
//由于上面已经通过npm安装了mysql模块,故可以直接导入使用
const mysql = require("mysql");
const dbConfig = {
//端口名称
host: "127.0.0.1",
//用户名
user: "root",
//密码
password: "root",
//端口:可以通过phpstudy软件查看并修改
port: "3306",
//需要操作的数据表
database: "project_flower"
}
const lianXi = mysql.createConnection(dbConfig);
lianXi.connect();
async function _excute(_sql) {
return await new Promise((resolve, reject) => {
lianXi.query(_sql, (err, res) => {
if (err) {
reject(err)
} else {
resolve(res)
}
})
})
}
module.exports = _excute;
(4)encryption:加密模块
作用:加密处理,参数1为需要加密的数据
//node提供的模块
const crypto = require("crypto")
//设置私钥
const _pwd = "2010406";
//加密处理
const encryption = (val) => {
return crypto.createHmac("md5", _pwd)
.update(val)
.digest("hex");
}
module.exports = encryption;
(5)judge.js:根据不同响应输出不同结果
作用:根据不同响应输出不同结果,参数1为需要返回的数据,参数2为输出的语句,参数3为状态码
function baseData(data, msg, code) {
//判断传入的data数据类型和msg数据类型,如果都为字符串,则只输出data中的数据
if (typeof data == "string" && typeof msg == "string") {
[data, msg] = [undefined, data]
}
return {
code,
msg,
data
}
}
//成功操作时调用
function successMoudle(data, msg = "成功操作") {
return baseData(data, msg, "200");
}
//失败操作时调用
function errorMoudle(data, msg = "失败操作") {
return baseData(data, msg, "409");
}
//缺少参数时调用
function lackMoudle(data, msg = "缺少参数") {
return baseData(`${data}`, msg, "400");
}
module.exports = {
successMoudle,
errorMoudle,
lackMoudle
}
4、开始配置路由
目前理解路由:路由即可以根据请求的地址不同,作出相应的反应,即中间交互层
接着在src文件夹中,新建一个router文件夹,用于存放路由层。在router文件夹中新建4个路由文件,分别为_user.js,appoint.js,session.js,date.js
更改app.js中的代码
const querystring = require("querystring")
const getBodyDate = require("./src/utils/getBodyDate")
//四个路由根据自身的相对路径分别导入
const _user = require("./src/router/_user")
const appoint = require("./src/router/appoint")
const session = require("./src/router/session")
const date = require("./src/router/date")
async function severHandle(req, res) {
res.setHeader("Content-type", "application/json")
if (req.method == "GET") {
req.query = querystring.parse(req.url.split("?")[1])
} else {
try {
req.body = await getBodyDate(req)
} catch (err) {
console.log(err);
}
}
req.path = req.url.split("?")[0]
//设置一个resData数组,用于接收响应过来的路由,记住一次只能响应一个,所以resData里面只有resData[0]才有数据,每个路由都需要将req作为参数传入
let resData = [await _user(req), await appoint(req), await session(req), await date(req)].filter(item => {
//只有响应过的路由才会被装入数组中
return item;
});
//将数据更改为响应过来的路由数据,但res.end只支持字符串格式,所以将数据进行JSON.stringify(resData)处理,否则会报错
res.end(JSON.stringify(resData))
}
module.exports = severHandle;
通过这种方式将四个路由层与app.js绑定了起来,由于路由层都是异步处理,所以在每个路由前面都加上了await。
(1)、_user.js
首先对于需求进行简单的分析:
1、我们要判断用户是登录还是注册,登录即请求方式为“GET”,路径为"/index/user/login"。
注册请求方式是“POST”,路径为"/index/user/create"。
2、由于用户登录传来的数据有可能格式不正确,我们需要借助正则表达式去作判断。
3、如果数据格式都无误,接下来就要进入处理层,对数据库进行操作
4、我们要根据数据库返回给我们的信息,知道是操作成功还是失败,进而进行不同的结果返回给用户
在_user.js中加入如下代码
//导入参数数据检测模块,用于检测参数的正确性
const checkData = require("../utils/checkData")
//该模块为路由响应的处理模块
const {
create,
login
} = require("../Control/userCreate")
//加密模块,将手机号和私钥进行加密,得到唯一的token
const encryption = require("../utils/encryption")
//响应不同结果模块
const {
successMoudle,
errorMoudle,
lackMoudle
} = require("../utils/judge")
async function _user(req) {
//判断请求方式为POST,请求路径为用户注册路径"/index/user/create"
if (req.method == "POST" && req.path == "/index/user/create") {
//先将参数传入检测模块中检测
let checkText = checkData(req, "name", "phone", "idcard")
if (checkText) {
//如果有参数不正确,则会返回相应的错误
return lackMoudle(checkText);
} else {
//将参数中手机号码传入进行加密,返回一个token值
req.body.token = encryption(req.body.phone);
//等待路由处理层与数据库进行数据交互,返回结果
let userData = await create(req);
if (userData) {
//成功操作后输出
return successMoudle("操作成功");
} else {
//失败操作后输出
return errorMoudle("操作失败");
}
}
}
if (req.method == "GET" && req.path == "/index/user/login") {
//用let声明的变量具有块级作用域,所以不会与上述声明的checkText发生冲突
let checkText = checkData(req, "name", "phone", "idcard")
if (checkText) {
return lackMoudle(checkText);
} else {
let userData = await login(req);
if (userData.length) {
return successMoudle(userData[0].token);
} else {
return errorMoudle("登录失败");
}
}
}
}
module.exports = _user
上述的create、login还未创建,它们都是路由处理层模块,下面我们进行创建。在src文件夹目录中创建一个Control文件夹,用于存放路由处理层文件
分别创建四个路由处理层模块,他们都将与他们父亲路由一一对应,
①userCreate.js
在userCreate.js中加入如下代码
//需要与数据库对接,所以要引入连接工具模块
const _excute = require("../utils/content")
//该模块为_user.js中POST请求的处理过程
async function create(req) {
//写一个sql语句,用于将其传入_excute模块中,与数据库进行交互
//INSERT INTO user (token,name,phone,idcard) VALUES :在数据库中添加一个数据,找到user表单,找到表单中token,name,phone,idcard,从req.body中拿到参数一一填入到表单
let sql = `INSERT INTO user (token,name,phone,idcard) VALUES ("${req.body.token}","${req.body.name}","${req.body.phone}","${req.body.idcard}")`;
try {
//如果操作成功,则返回相应的结果
return await _excute(sql);
} catch (error) {
//如果操作失败,捕捉错误,返回一个false
return false;
}
}
//login方法与create方法差不多,只是mysql语句有变化
async function login(req) {
//查找token值,在user表单中,查询条件为name,phone和idcard
let sql = `SELECT token FROM user WHERE name="${req.query.name}" AND phone="${req.query.phone}" AND idcard="${req.query.idcard}"`;
console.log(sql);
try {
return await _excute(sql);
} catch (error) {
return false;
}
}
//将这两个模块以对象导出到_user.js中进行使用
module.exports = {
create,
login
};
打开postman
更改为post请求,路径为“http://localhost:3000/index/user/create”,post请求参数需要在下方的body中输入,并且为严格模式,要加上双引号。运行send,即可看到操作成功。
此时打开mysql数据表中的user表,即可看到添加了一条新的用户
如果重复添加,则会返回操作失败
如果数据格式不正确,则会返回对应的错误信息
get请求方式有所不同,它的参数是放在地址栏里面并用?开始传参,各个参数之间用&符号隔开如图
此时请求返回的是查找对象的token值。
(2)、appoint.js
与_user路由大同小异
在appoint.js文件加入如下代码
//引入检测参数模块
const checkData = require("../utils/checkData");
//路由处理层
const {
create,
login,
dd
} = require("../Control/appointCreate");
const {
successMoudle,
errorMoudle,
lackMoudle
} = require("../utils/judge");
//连接数据库模块
const _excute = require("../utils/content");
//该方法用于查询场次信息,是否能被预约,预约时间等
async function getTimeById(req) {
//根据场次id查找所有符合对象的值
let sql = `SELECT * FROM session WHERE id="${req.body.sessionId}"`;
try {
return await _excute(sql);
} catch (error) {
return false;
}
}
//查询用户信息,用于得知他是否预约
async function appointCheckData(req) {
//根据用户的token查询他之前是否有预约
let sql = `SELECT is_appointment FROM user WHERE token="${req.body.token}"`;
try {
return await _excute(sql);
} catch (error) {
return false;
}
}
//使用put方式让用户进行预约
async function appoint(req) {
if (req.method == "PUT" && req.path == "/index/appointment/create") {
//检测参数是否正确
let checkText = checkData(req, "token", "sessionId");
if (checkText) {
return lackMoudle(checkText)
} else {
//先查询预约的id是否存在,不存在则返回场次信息不存在
let sessionTime = await getTimeById(req);
if (sessionTime && sessionTime.length) {
//查询场次是否被别人预约,已被预约返回已经预约
if (sessionTime[0].is_appointment) {
//保存预约场次的开始时间
req.body.session_time = sessionTime[0].start_time;
//当场次信息都无误满足时,即可调用预约模块,将数据导入,并返回预约成功
let appointData = await create(req);
if (appointData && appointData.changedRows) {
return successMoudle("预约成功")
} else {
return errorMoudle("已经预约")
}
} else {
return errorMoudle("该场次已经满人")
}
} else {
return errorMoudle("场次信息不存在")
}
}
}
//get请求查询用户的预约信息
if (req.method == "GET" && req.path == "/index/appointment/get") {
let checkText = checkData(req, "token")
if (checkText) {
return lackMoudle(checkText);
} else {
//查询路由处理层
let appointData = await login(req);
if (appointData.length) {
return successMoudle(appointData)
} else {
return errorMoudle("查询失败")
}
}
}
//使用delete删除用户之前的预约信息
if (req.method == "DELETE" && req.path == "/index/appointment/delete") {
let checkText = await appointCheckData(req)
if (checkText[0].is_appointment == 1) {
//dd为路由处理层,重置is_appointment为0,表示可以预约
let appointData = await dd(req);
if (appointData) {
return successMoudle("取消预约成功")
}
} else {
return errorMoudle("您还没预约")
}
}
}
module.exports = appoint
②appointCreate.js
下面为appoint.js响应的路由处理层代码
const _excute = require("../utils/content")
async function create(req) {
//创建一个新的预约信息,根据用户凭证
let sql = `UPDATE user SET sessions_id ="${req.body.sessionId}",sessions_time="${req.body.session_time}",is_appointment=1 WHERE token ="${req.body.token}"`;
try {
return await _excute(sql);
} catch (err) {
return false;
}
}
async function login(req) {
//查询全部的预约信息
let sql = `SELECT * FROM user WHERE token="${req.query.token}"`;
try {
return await _excute(sql);
} catch (err) {
return false;
}
}
async function dd(req) {
//重置预约信息
let sql = `UPDATE user SET is_appointment=0,sessions_time=null,sessions_id=null WHERE token ="${req.body.token}"`;
try {
return await _excute(sql);
} catch (err) {
return false;
}
}
module.exports = {
create,
login,
dd
};
1、put请求为添加预约场次
两个参数,参数1为用户凭证,参数2为预约的场次id
此时可以在用户信息中看见预约成功了
2、get查询预约信息,通过token值即可查询
参数为用户凭证token
查询成功后返回预约的所有信息
3、delete为删除用户的预约信息,需要修改该用户的is_appointment,sessions_time,session_id的值,将他们重置
参数为用户凭证token,根据用户凭证去重置预约信息
可以看到之前的预约信息已经被重置了
(3)、date.js
const {
create,
login
} = require("../Control/dateCreate");
const checkData = require("../utils/checkData");
const {
successMoudle,
errorMoudle,
lackMoudle
} = require("../utils/judge");
async function date(req) {
if (req.method == "POST" && req.path == "/admin/date/create") {
let checkText = checkData(req, "id", "date")
if (checkText) {
return lackMoudle(checkText)
} else {
//将日期对象转换成时间戳存入到数据库中
req.body.lastdate = new Date(req.body.date).getTime();
//调用日期路由处理层模块,修改mysql数据库
let dateData = await create(req);
if (dateData) {
return successMoudle("成功添加");
} else {
return errorMoudle("添加失败")
}
}
}
if (req.method == "GET" && req.path == "/index/date/get") {
//通过login与数据库交互,查询数据
let dateData = await login(req);
if (dateData.length) {
//如果查到,则返回查到的结果
return successMoudle(dateData)
} else {
return errorMoudle("查询失败")
}
}
}
module.exports = date;
③dateCreate.js
const _excute = require("../utils/content");
async function create(req) {
//在time表单中找到id和time,分别传入参数req.body.id和req.body.lastdate
let sql = `INSERT INTO time (id,time) VALUES ("${req.body.id}","${req.body.lastdate}")`;
try {
return await _excute(sql);
} catch (err) {
return false;
}
}
async function login(req) {
//返回查到的所有信息*,来自time表单,查询条件为id
let sql = `SELECT * FROM time WHERE id="${req.query.id}"`;
try {
return await _excute(sql);
} catch (err) {
return false;
}
}
module.exports = {
create,
login
}
post请求为添加一条时间信息,参数1为传入id,不可重复,参数2为日期
正确填写参数即可在数据库中成功添加
重复添加会导致添加失败
(4)、session.js
const checkData = require("../utils/checkData");
const {
successMoudle,
errorMoudle,
lackMoudle
} = require("../utils/judge");
const {
create,
login
} = require("../Control/sessionCreate");
async function session(req) {
if (req.method == "POST" && req.path == "/admin/session/create") {
//传入相应参数进行检测
let checkText = checkData(req, "startTime", "endTime", "dateId", "maxSize", "date");
if (checkText) {
return lackMoudle(checkText);
} else {
//将传入参数的时间和日期拼接起来并返回时间戳
req.body.startTimeStemp = new Date(req.body.date + " " + req.body.startTime).getTime();
req.body.endTimeStamp = new Date(req.body.date + " " + req.body.endTime).getTime();
//调用
let sessionData = await create(req);
if (sessionData) {
return successMoudle("成功添加")
} else {
return errorMoudle("添加失败")
}
}
}
if (req.method == "GET" && req.path == "/index/session/get") {
let checkText = checkData(req, "dateId")
if (checkText) {
return lackMoudle(checkText);
} else {
let sessionData = await login(req)
if (sessionData.length) {
return successMoudle(sessionData)
} else {
return errorMoudle("查询失败")
}
}
}
}
module.exports = session;
④sessionCreate.js
const _excute = require("../utils/content");
async function create(req) {
//将数据一一对应插入
let sql = `INSERT INTO session (start_time,end_time,time_id, all_num) VALUES ("${req.body.startTimeStemp}","${req.body.endTimeStamp}","${req.body.dateId}","${req.body.maxSize}")`;
try {
return await _excute(sql);
} catch (err) {
console.log(err);
return false;
}
}
async function login(req) {
//通过场次id寻找并返回所有符合条件的值
let sql = `SELECT * FROM session WHERE time_id="${req.query.dateId}" `;
try {
return await _excute(sql);
} catch (err) {
console.log(err);
return false;
}
}
module.exports = {
create,
login
};
post填写正确的参数格式,即可在数据库中插入一条场次信息
数据库中成功添加场次信息
get请求根据场次id查询满足条件的场次信息
5、mysql语句总结
一、增加
INSERT INTO 表单名称 (id,time) VALUES ("${req.body.id}","${req.body.lastdate}")
id和time都为表单中可以传入的值,需要参数一一对应的去传入
二、改
UPDATE 表单名称 SET is_appointment=0,sessions_time=null,sessions_id=null WHERE token ="${req.body.token}
set为需要更改的表单中"数据的名称=改的值",多个值之间用“,”隔开,where为表单中查找条件
三、查
SELECT * FROM 表单名称 WHERE id="${req.query.id}
*为全部的数据,可以设置表单中任意你需要查询的值,where为查找的条件,多个条件之间用"and"连接。
四、删除
DELETE FROM 表单名称 WHERE 条件
使用删除将会删除整行代码
总结
诺上述代码有错误或者需要修改的地方请及时反馈
内容总结
以上是互联网集市为您收集整理的近期学习node.js的总结全部内容,希望文章能够帮你解决近期学习node.js的总结所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。