您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“怎么在Node中構(gòu)建一個輕量級的位置分析報告服務(wù)API”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“怎么在Node中構(gòu)建一個輕量級的位置分析報告服務(wù)API”這篇文章吧。
由經(jīng)緯度定義的位置,可以與其他數(shù)據(jù)結(jié)合使用,為企業(yè)產(chǎn)生洞察力,這就是所謂的位置分析。
在全球范圍內(nèi)經(jīng)營的企業(yè)在整個價值鏈中使用位置分析,例如,用于定位用戶、提供服務(wù)和運(yùn)行目標(biāo)廣告。隨著社交媒體和移動設(shè)備的興起,位置分析的使用在全球范圍內(nèi)有所增加。
在本教程中,我們將學(xué)習(xí)如何在Node.js中構(gòu)建一個輕量級的位置分析報告服務(wù)API。在本教程結(jié)束時,你將能夠為自己的項目構(gòu)建這種類型的API。你也會對Node.js中的錯誤處理和良好的文件結(jié)構(gòu)有更好的理解
讓我們開始吧!
要繼續(xù)學(xué)習(xí)本教程,你需要具備以下條件。
熟悉Node.js、Express和Git
Visual Studio代碼編輯器
Heroku賬戶
Postman賬戶
首先,我們需要設(shè)置我們的文件結(jié)構(gòu)。打開你的終端,創(chuàng)建一個新的目錄,你將在其中存儲項目的所有文件。在你的終端,鍵入以下命令,后面跟著文件夾的名稱,lars
。
mkdir lars
在VS代碼編輯器中打開lars
工作目錄。
code .
你會看到你的VS Code窗口打開。
Visual Studio Code 窗口
通過在Visual Studio中打開你的終端并運(yùn)行npm init -y
,初始化工作目錄。
如果你想在VS Code之外的操作系統(tǒng)的終端中運(yùn)行這個命令,請導(dǎo)航到lars
目錄并運(yùn)行下面的命令。
npm init -y
上面的代碼自動生成了package.json
文件。
VS Code顯示創(chuàng)建的package.json文件
在本教程中,我們將使用Express作為一個依賴項。通過運(yùn)行下面的命令來安裝Express。
npm install express --save
將Express作為依賴關(guān)系安裝的命令
安裝完Express后,你會注意到一個node_modules
文件夾被創(chuàng)建了。為了確認(rèn)你已經(jīng)安裝了Express,請檢查你的package.json
文件,你會看到Express作為一個依賴項被安裝。
node_modules文件夾被創(chuàng)建,Express被添加到package.json中。
我們需要將Express導(dǎo)入我們的應(yīng)用程序,因為它是一個npm模塊。在與你的package.json
文件相同的目錄下創(chuàng)建一個名為app.js
的新文件。
VS代碼窗口的截圖顯示app.js已經(jīng)創(chuàng)建。
在你的app.js
文件中,通過運(yùn)行下面的代碼require
Express。
const express = require('express');
導(dǎo)入Express
現(xiàn)在,調(diào)用Express來創(chuàng)建你的應(yīng)用、路由和你的應(yīng)用要運(yùn)行的端口。
const app = express();
Node.js實(shí)現(xiàn)了模塊化,這意味著它將你的應(yīng)用分成模塊,或各種文件,并導(dǎo)出每個文件。我們將使用export
關(guān)鍵字導(dǎo)出app
。
module.exports = app;
app.js文件
接下來,在與app.js
文件相同的目錄下創(chuàng)建另一個名為server.js
的文件。Require
將app.js
文件導(dǎo)入server.js
文件。
const app = require('./app');
在與server.js
相同的目錄中創(chuàng)建一個名為config.env
的文件。config.env
文件將包含我們的應(yīng)用程序需要的所有 [process.env](https://nodejs.org/dist/latest-v8.x/docs/api/process.html)
我們的應(yīng)用程序需要的所有密鑰。在config.env
文件中,創(chuàng)建一個PORT
變量,并將PORT
設(shè)置為監(jiān)聽端口8000
。
PORT=8000
導(dǎo)入應(yīng)用程序后,在server.js
文件中創(chuàng)建一個名為port
的常量。將其設(shè)置為你剛剛創(chuàng)建的PORT
變量和一個默認(rèn)的端口3000
。
const port = process.env.PORT || 3000;
最后,我們將用.listen()
方法設(shè)置應(yīng)用程序在該端口上監(jiān)聽。
app.listen(port, () => { console.log(`App listening on ${port}`) });
每當(dāng)你訪問一個網(wǎng)頁或一個在網(wǎng)絡(luò)上運(yùn)行的應(yīng)用程序時,你都在發(fā)出一個HTTP請求。服務(wù)器用來自后臺或數(shù)據(jù)庫的數(shù)據(jù)進(jìn)行響應(yīng),這就是所謂的HTTP響應(yīng)。
當(dāng)你在一個網(wǎng)絡(luò)應(yīng)用程序上創(chuàng)建一個資源時,你正在調(diào)用POST
請求。同樣地,如果你試圖刪除或更新一個Web應(yīng)用上的資源,你正在調(diào)用DELETE
、PATCH
、或UPDATE
請求。讓我們建立路由來處理這些請求。
在你的工作目錄中創(chuàng)建一個名為routes
的文件夾,并在其中創(chuàng)建一個名為analyticsRoute.js
的文件。Require
在analyticsRoute.js
文件中表達(dá),以設(shè)置API的路由。
const express = require('express');
我們還需要從app.js
文件中require
我們的應(yīng)用程序模塊。
const app = require('../app');
然后,我們創(chuàng)建我們的路由。
const router = express.Router();
最后,我們要導(dǎo)出路由器。
module.exports = router;
我們需要為控制器創(chuàng)建文件,將其導(dǎo)入我們的analyticsRoutes
文件。首先,在你的工作目錄中創(chuàng)建一個名為controllers
的文件夾。
我們的API將使用用戶提供的IP地址和坐標(biāo)來計算距離和位置。我們的請求需要接受這些信息和來自用戶的請求。
我們將使用一個POST
請求,因為用戶在req.body
。為了保存這些信息,我們需要在控制器中require
一個fs
模塊(文件系統(tǒng))。
POST
的請求在controllers
文件夾中創(chuàng)建一個名為storeController.js
的文件。在storeController.js
文件中,我們需要導(dǎo)入fs
模塊和fsPromises.readFile()
方法來處理返回的promise
,也就是用戶的IP地址和坐標(biāo)。
要安裝fs
模塊,在你的工作目錄中打開你的終端,運(yùn)行以下命令。
npm i fs --save
在你的文件頂部輸入以下代碼。
const fsp = require('fs').promises; const fs = require('fs');
接下來,我們將創(chuàng)建一個控制器,處理我們的POST
請求的路由。我們將使用exports
關(guān)鍵字并創(chuàng)建一個接受三個參數(shù)的異步中間件函數(shù)。
req
: 代表請求對象
res
: 代表響應(yīng)對象
next
: 函數(shù)在中間件輸出后立即被調(diào)用。
postAnalytics = async(req, res, next) => {}
現(xiàn)在,我們將把req.body
中的數(shù)據(jù)對象的屬性保存到reportAnalytics
數(shù)組中。我們將設(shè)置一個Date()
對象,將任何數(shù)據(jù)的創(chuàng)建日期保存在一個createdAt
關(guān)鍵中。
reportAnalytics.push({...req.body, createdAt: new Date()});
我們將創(chuàng)建一個名為storeAnalytics.json
的文件,使用JSON.stringify()
,將我們的reportAnalytics
數(shù)組的內(nèi)容保存為一個字符串。
await fsp.writeFile(`${__dirname}/storeAnalytics.json`, JSON.stringify(reportAnalytics));
當(dāng)用戶提出POST
要求時,我們需要檢查storeAnalytics.json
文件是否存在。如果該文件存在,我們需要讀取該文件并保存輸出。
輸出包含一個名為reportFile
的常量,它存儲了被讀取的文件內(nèi)容。在reportFile
,使用JSON.parse
,將文件的內(nèi)容轉(zhuǎn)換為一個JavaScript對象。
// checks if file exists if (fs.existsSync(`${__dirname}/storeAnalytics.json`)) { // If the file exists, reads the file const reportFile = await fsp.readFile(`${__dirname}/storeAnalytics.json`, 'utf-8') // converts the file to JavaScript Object reportAnalytics = JSON.parse(reportFile) } else { // if file does not exist return ('File does not exist'); }
該 [fs.existsSync()](https://www.geeksforgeeks.org/node-js-fs-existssync-method/)
方法同步地檢查文件是否存在。它接受${__dirname}/storeAnalytics.json
路徑作為其單一參數(shù),并指向我們要檢查的文件的位置。
我們將await
關(guān)鍵字與reportFile
,以等待用fsp.readFile()
方法讀取文件的結(jié)果。接下來,我們用(${__dirname}/storeAnalytics.json
來指定我們要讀取的文件的路徑。我們將編碼格式設(shè)置為utf-8
,這將把從文件中讀取的內(nèi)容轉(zhuǎn)換為一個字符串。
JSON.parse()
將reportFile
轉(zhuǎn)換為JavaScript對象,并將其存儲在reportAnalytics
數(shù)組中。else
語句塊中的代碼只有在文件不存在時才會運(yùn)行。最后,我們使用了return
語句,因為我們想在代碼運(yùn)行后停止函數(shù)的執(zhí)行。
如果文件被成功讀取、創(chuàng)建并保存在storeAnalytics.json
,我們需要發(fā)送一個響應(yīng)。我們將使用響應(yīng)對象(res)
,它是我們的異步postAnalytics
函數(shù)的第二個參數(shù)。
res.status(201).json({ status: 'success', data: { message: 'IP and Coordinates successfully taken' } })
我們將用一個狀態(tài)success
和數(shù)據(jù)信息IP and Coordinates successfully taken
來響應(yīng)。
你的storeController.js
文件應(yīng)該看起來像下面的屏幕截圖。
GET
的請求我們需要創(chuàng)建另一個控制器文件來處理我們的GET
請求。當(dāng)用戶向API發(fā)出GET
請求時,我們將根據(jù)他們的IP地址和坐標(biāo)來計算他們的位置。
在controllers
文件夾中創(chuàng)建一個名為fetchController.js
的文件。fs
在storeController.js
文件中,我們需要require
模塊和fsPromises.readFile()
方法來處理返回的promise
。
const fsp = require('fs').promises; const fs = require('fs');
讓我們創(chuàng)建控制器來處理我們對GET
請求的路由。我們將使用類似的中間件函數(shù)和參數(shù)來處理上面的POST
請求。
exports.getAnalytics = async(req, res, next) => {}
在getAnalytics
中間件中,輸入以下代碼,從請求的查詢中獲得IP地址。
const { ip } = req.query;
現(xiàn)在,創(chuàng)建一個空數(shù)組,用來存儲req.body
的內(nèi)容。
let reportAnalytics = [];
正如我們之前所做的,我們需要檢查storeAnalytics.json
文件是否存在。如果文件存在,我們將在reportFile
上使用JSON.parse
,將文件內(nèi)容轉(zhuǎn)換為一個JavaScript對象。
if (fs.existsSync(`${__dirname}/storeAnalytics.json`)) { const reportFile = await fsp.readFile(`${__dirname}/storeAnalytics.json`, 'utf-8') reportAnalytics = JSON.parse(reportFile) } else { return ('File does not exist'); }
現(xiàn)在,我們可以在storeAnalytics.json
文件中保存用戶的IP地址和坐標(biāo)。任何時候用戶請求根據(jù)提供的坐標(biāo)計算地理位置,IP地址將以查詢的形式包含在請求中。
現(xiàn)在我們已經(jīng)從req.query
對象中得到了IP地址,我們可以編寫代碼來檢查req.query
對象中提供的IP地址是否與存儲在storeAnalytics.json
文件中的IP地址相同。
for (let i=0; i<reportAnalytics.length; i++) { if (reportAnalytics[i].ip !== ip) { return ('No Coordinates found with that IP'); }; }
在上面的代碼中,我們使用forloop
來循環(huán)瀏覽reportAnalytics
數(shù)組。我們將變量i
,代表當(dāng)前元素在reportAnalytics
數(shù)組中的索引,初始化為0
。如果i小于reportAnalytics
數(shù)組的長度,我們將其遞增。
接下來,我們檢查reportAnalytics
數(shù)組的IP地址屬性是否等于req.query
中提供的IP地址。
讓我們計算一下只在最后一小時內(nèi)存儲的IP地址的位置。
const hourAgo = new Date(); hourAgo.setHours(hourAgo.getHours()-1); const getReport = reportAnalytics.filter(el => el.ip === ip && new Date(el.createdAt) > hourAgo )
在上面的代碼塊中,我們創(chuàng)建了一個名為hourAgo
的常量,并將其設(shè)置為一個Date
對象。我們使用setHours()
方法將hourAgo
設(shè)置為最后一個小時的getHours()-1
。
當(dāng)reportAnalytics
文件中的當(dāng)前IP地址等同于或等于req.query
中傳遞的IP地址時,意味著數(shù)據(jù)是在最后一小時內(nèi)創(chuàng)建的,getReport
創(chuàng)建一個常量,設(shè)置為一個新的數(shù)組。
創(chuàng)建一個名為coordinatesArray
的常量,它將只存儲已經(jīng)保存在getReport
數(shù)組中的坐標(biāo)。
const coordinatesArray = getReport.map(element => element.coordinates)
接下來,我們需要用坐標(biāo)計算出位置。我們需要遍歷coordinatesArray
,通過傳入保存為坐標(biāo)的兩個值來計算位置。
let totalLength = 0; for (let i=0; i<coordinatesArray.length; i++) { if (i == coordinatesArray.length - 1) { break; } let distance = calculateDistance(coordinatesArray[i], coordina tesArray[i+1]); totalLength += distance; }
在上面的代碼中,totalLength
代表從兩個坐標(biāo)計算出來的總距離。為了遍歷coordinatesArray
,我們需要初始化我們的計算結(jié)果。將totalLength
設(shè)置為零,初始化總距離。
第二行包含我們使用的迭代代碼forloop
。我們用let i=0
來初始化i
變量。i
變量代表當(dāng)前元素在coordinatesArray
的索引。
i<coordinatesArray.length
設(shè)置迭代的條件,只有當(dāng)當(dāng)前元素的索引小于coordinatesArray
的長度時才運(yùn)行。接下來,我們在迭代中增加當(dāng)前元素的索引,以移動到下一個元素,i++
。
接下來,我們將檢查當(dāng)前元素的索引是否等于數(shù)組中最后一個元素的編號。然后,我們暫停迭代代碼的執(zhí)行,用break
關(guān)鍵字移動到下一個。
最后,我們創(chuàng)建一個名為calculateDistance
的函數(shù),接受兩個參數(shù),即第一和第二坐標(biāo)值(經(jīng)度和緯度)。我們將在另一個模塊中創(chuàng)建calculateDistance
,并將其導(dǎo)出到fetchController.js
文件中,然后我們將最終結(jié)果保存在我們初始化的totalLength
變量中。
注意,每個請求都需要一個響應(yīng)。我們將用一個200
的statusCode
和一個包含我們將計算的距離值的JSON來響應(yīng)。只有在代碼成功的情況下才會顯示響應(yīng)。
res.status(200).json({distance: totalLength})
你的fetchController.js
文件應(yīng)該看起來像下面兩個代碼塊。
fetchController.js文件
fetchController.js文件的續(xù)篇
calculateDistance
函數(shù)在你的工作目錄中,創(chuàng)建一個名為utilities
的新文件夾,在里面創(chuàng)建一個名為calculateDistance.js
的文件。打開calculateDistance.js
文件,添加以下函數(shù)。
const calculateDistance = (coordinate1, coordinate2) => { const distance = Math.sqrt(Math.pow(Number(coordinate1.x) - Number(coordinate2.x), 2) + Math.pow(Number(coordinate1.y) - Number(coordinate2.y), 2)); return distance; } module.exports = calculateDistance;
在第一行,我們創(chuàng)建一個名為calculateDistance
的函數(shù),它接受兩個參數(shù):coordinate1
和coordinate2
。它使用下面的方程式。
Math.sqrt
: 數(shù)學(xué)中的平方根
Math.pow
:將一個數(shù)字提高到一個冪值
Number()
: 將一個值轉(zhuǎn)換為一個數(shù)字
coordinate1.x
:第一個坐標(biāo)(經(jīng)度)的第二個值
coordinate2.x
:第一個坐標(biāo)的第一個值(經(jīng)度)。
coordinate1.y
:第二個坐標(biāo)的第二個值(緯度)。
coordinate2.y
:第二個坐標(biāo)的第一個值(緯度)。
現(xiàn)在我們已經(jīng)創(chuàng)建了calculateDistance
函數(shù),我們需要將該函數(shù)require
到我們fetchController.js
文件的代碼中。在fs
模塊之后添加下面的代碼。
const calculateDistance = require('../utilities/calculateDistance');
實(shí)現(xiàn)錯誤處理是很重要的,以防止我們的代碼失敗或某個特定的實(shí)現(xiàn)沒有按照設(shè)計的方式工作。我們將在開發(fā)和生產(chǎn)中添加錯誤處理。
打開你的config.env
文件,運(yùn)行NODE_ENV=development
,將環(huán)境設(shè)置為開發(fā)。
在你的controllers
文件夾中,創(chuàng)建一個名為errorController.js
的新文件。下面的代碼片斷創(chuàng)建了一個名為sendErrorDev
的函數(shù),以處理在開發(fā)環(huán)境中遇到的錯誤。
const sendErrorDev = (err, res) => { res.status(err.statusCode).json({ status: err.status, error: err, message: err.message, stack: err.stack, }); }
我們將創(chuàng)建一個名為sendErrorDev
的函數(shù),它接受兩個參數(shù),err
表示錯誤,res
表示響應(yīng)。response.status
接收錯誤的statusCode
,并以JSON數(shù)據(jù)進(jìn)行響應(yīng)。
此外,我們將創(chuàng)建一個名為sendErrorProd
的函數(shù),它將處理API在生產(chǎn)環(huán)境中遇到的錯誤。
const sendErrorProd = (err, res) => { if(err.isOperational) { res.status(err.statusCode).json({ status: err.status, message: err.message }); } else { console.error('Error', err); res.status(500).json({ status: 'error', message: 'Something went wrong' }) } }
在你的utilities
文件夾中,創(chuàng)建一個名為appError.js
的文件,并輸入以下代碼。
class AppError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error'; this.isOperational = true; Error.captureStackTrace(this, this.constructor); } } module.exports = AppError;
我們將創(chuàng)建一個名為AppError
的類,它擴(kuò)展了Error
對象。
然后,我們將創(chuàng)建一個構(gòu)造函數(shù),它將初始化該類的對象。它接受兩個參數(shù),叫做message
和statusCode
。super
方法用一個參數(shù)調(diào)用構(gòu)造函數(shù),將其傳入message
,并獲得對構(gòu)造函數(shù)的屬性和方法的訪問。
接下來,我們將構(gòu)造函數(shù)的statusCode
屬性設(shè)置為statusCode
。我們將構(gòu)造函數(shù)的status
屬性設(shè)置為任何以4
開始的statusCode
,例如,將404 statusCode
設(shè)置為fail
或error
。
創(chuàng)建另一個名為catchAsync.js
的文件,并在其中添加以下代碼。
module.exports = fn => { return (req, res, next) => { fn(req, res, next).catch(next); } }
Require
appError.js
文件和catchAsync.js
文件在你的storeController.js
和fetchController.js
文件中。將這兩條導(dǎo)入語句放在兩個文件中的代碼頂部。
const catchAsync = require('../utilities/catchAsync'); const AppError = require('../utilities/appError');
在storeController.js
和fetchController.js
文件中,用catchAsync()
方法包裝你的函數(shù),如下所示。
// For storeController.js file exports.postAnalytics = catchAsync(async(req, res, next) => {...} // For fetchController.js file exports.getAnalytics = catchAsync(async(req, res, next) => {...}
接下來,在你的fetchController.js
文件中,運(yùn)行AppError
類。
for (let i=0; i<reportAnalytics.length; i++) { if (reportAnalytics[i].ip !== ip) { return next(new AppError('No Coordinates found with that IP', 404)); }; }
接下來,在你的storeController.js
文件中運(yùn)行AppError
類。
if (fs.existsSync(`${__dirname}/storeAnalytics.json`)) { const reportFile = await fsp.readFile(`${__dirname}/storeAnalytics.json`, 'utf-8') reportAnalytics = JSON.parse(reportFile) } else { return next(new AppError('File does not exist', 404)); }
你的storeController.js
和fetchController.js
文件中的代碼應(yīng)該看起來像下面的截圖。
storeController.js文件的屏幕截圖
fetchController.js文件第1-32行
fetchController.js文件第33-37行
我們需要驗證在req.body
,其中包括IP地址和坐標(biāo)的數(shù)據(jù),是正確的,而且格式正確。坐標(biāo)應(yīng)該至少有兩個值,代表經(jīng)度和緯度。
在utilities
文件夾中,創(chuàng)建一個名為Validation
的新文件夾。在Validation
文件夾中,創(chuàng)建一個名為schema.js
的文件。schema.js
文件將包含req.body
中提供的任何數(shù)據(jù)的所需格式。我們將使用 [joi](https://www.npmjs.com/package/joi)
驗證器。
npm install joi
在schema.js
文件中輸入以下代碼。
const Joi = require('joi'); const schema = Joi.object().keys({ ip: Joi.string().ip().required(), coordinates: Joi.object({ x: Joi.number().required(), y: Joi.number().required() }).required() }) module.exports = schema;
joi
在上面的代碼塊中,我們require
驗證器,用它來創(chuàng)建我們的模式。然后,我們將IP地址設(shè)置為總是一個字符串,并通過在請求體中要求它來驗證IP地址。
我們將坐標(biāo)設(shè)置為object
。我們將代表經(jīng)度和緯度值的x
和y
值都設(shè)置為數(shù)字,并將其require
,以便我們的代碼運(yùn)行。最后,我們導(dǎo)出了模式。
在驗證器文件夾中,創(chuàng)建另一個名為validateIP.js
的文件。在里面,我們將編寫代碼來驗證IP地址,使用 [is-ip](https://www.npmjs.com/package/is-ip)
npm包。讓我們把這個包導(dǎo)出到我們的代碼中。
在validateIP.js
文件中,添加以下代碼。
const isIp = require('is-ip'); const fsp = require('fs').promises; const fs = require('fs'); exports.validateIP = (req, res, next) => { if(isIp(req.query.ip) !== true) { return res.status(404).json({ status: 'fail', data: { message: 'Invalid IP, not found.' } }) } next(); }
運(yùn)行以下命令,為我們的API安裝必要的依賴項。
npm install body-parser cors dotenv express fs is-ip joi morgan ndb nodemon
你的app.js
文件應(yīng)該看起來像下面的屏幕截圖。
app.js文件
在你的package.json
文件中的scripts
部分下,添加以下代碼片段。
"start:dev": "node server.js", "debug": "ndb server.js"
你的package.json
文件應(yīng)該看起來像下面的截圖。
package.json文件
用以下代碼更新你的analyticsRoute.js
文件。
const express = require('express'); const app = require('../app'); const router = express.Router(); const validateIP = require('../utilities/Validation/validateIP'); const storeController = require('../controllers/storeController'); const fetchController = require('../controllers/fetchController'); router.route('/analytics').post(storeController.postAnalytics).get(validateIP.validateIP, fetchController.getAnalytics); module.exports = router;
現(xiàn)在,我們已經(jīng)完成了我們的位置分析API的構(gòu)建!現(xiàn)在,讓我們測試一下我們的代碼,以確保它的工作。
我們將使用Postman來測試我們的API。讓我們啟動我們的API以確保它在我們的終端中運(yùn)行。
node server.js
你會在你的終端看到以下輸出。
終端
我們的API托管在Heroku上,它的最終輸出應(yīng)該看起來像下面的輸出。
你可以自己在托管的文檔中測試這個API。
https://documenter.getpostman.com/view/13856921/TzXumeXS
以上是“怎么在Node中構(gòu)建一個輕量級的位置分析報告服務(wù)API”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。