久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      本篇文章給大家分享一個(gè)實(shí)戰(zhàn),介紹一下在Node中構(gòu)建一個(gè)位置分析報(bào)告API的方法,在本教程結(jié)束時(shí),你也會(huì)對(duì)Node.js中的錯(cuò)誤處理和良好的文件結(jié)構(gòu)有更好的理解,希望對(duì)大家有所幫助!

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      由經(jīng)緯度定義的位置,可以與其他數(shù)據(jù)結(jié)合使用,為企業(yè)產(chǎn)生洞察力,這就是所謂的位置分析。

      在全球范圍內(nèi)經(jīng)營(yíng)的企業(yè)在整個(gè)價(jià)值鏈中使用位置分析,例如,用于定位用戶、提供服務(wù)和運(yùn)行目標(biāo)廣告。隨著社交媒體和移動(dòng)設(shè)備的興起,位置分析的使用在全球范圍內(nèi)有所增加。

      在本教程中,我們將學(xué)習(xí)如何在Node.js中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API。在本教程結(jié)束時(shí),你將能夠?yàn)樽约旱捻?xiàng)目構(gòu)建這種類(lèi)型的API。你也會(huì)對(duì)Node.js中的錯(cuò)誤處理和良好的文件結(jié)構(gòu)有更好的理解

      讓我們開(kāi)始吧!

      前提條件

      要繼續(xù)學(xué)習(xí)本教程,你需要具備以下條件。

      • 熟悉Node.js、Express和Git
      • Visual Studio代碼編輯器
      • Heroku賬戶
      • Postman賬戶

      設(shè)置文件結(jié)構(gòu)

      首先,我們需要設(shè)置我們的文件結(jié)構(gòu)。打開(kāi)你的終端,創(chuàng)建一個(gè)新的目錄,你將在其中存儲(chǔ)項(xiàng)目的所有文件。在你的終端,鍵入以下命令,后面跟著文件夾的名稱,lars 。

      mkdir lars

      在VS代碼編輯器中打開(kāi)lars 工作目錄。

        code .

      你會(huì)看到你的VS Code窗口打開(kāi)。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      Visual Studio Code 窗口

      通過(guò)在Visual Studio中打開(kāi)你的終端并運(yùn)行npm init -y ,初始化工作目錄。

      如果你想在VS Code之外的操作系統(tǒng)的終端中運(yùn)行這個(gè)命令,請(qǐng)導(dǎo)航到lars 目錄并運(yùn)行下面的命令。

      npm init -y

      上面的代碼自動(dòng)生成了package.json 文件。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      VS Code顯示創(chuàng)建的package.json文件

      在本教程中,我們將使用Express作為一個(gè)依賴項(xiàng)。通過(guò)運(yùn)行下面的命令來(lái)安裝Express。

      npm install express --save

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      將Express作為依賴關(guān)系安裝的命令

      安裝完Express后,你會(huì)注意到一個(gè)node_modules 文件夾被創(chuàng)建了。為了確認(rèn)你已經(jīng)安裝了Express,請(qǐng)檢查你的package.json 文件,你會(huì)看到Express作為一個(gè)依賴項(xiàng)被安裝。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      node_modules文件夾被創(chuàng)建,Express被添加到package.json中。

      我們需要將Express導(dǎo)入我們的應(yīng)用程序,因?yàn)樗且粋€(gè)npm模塊。在與你的package.json 文件相同的目錄下創(chuàng)建一個(gè)名為app.js 的新文件。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      VS代碼窗口的截圖顯示app.js已經(jīng)創(chuàng)建。

      在你的app.js 文件中,通過(guò)運(yùn)行下面的代碼requireExpress。

      const express = require('express');

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      導(dǎo)入Express

      現(xiàn)在,調(diào)用Express來(lái)創(chuàng)建你的應(yīng)用、路由和你的應(yīng)用要運(yùn)行的端口。

      const app = express();

      Node.js實(shí)現(xiàn)了模塊化,這意味著它將你的應(yīng)用分成模塊,或各種文件,并導(dǎo)出每個(gè)文件。我們將使用export 關(guān)鍵字導(dǎo)出app 。

      module.exports = app;

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      app.js文件

      接下來(lái),在與app.js 文件相同的目錄下創(chuàng)建另一個(gè)名為server.js 的文件。Requireapp.js 文件導(dǎo)入server.js 文件。

      const app = require('./app');

      在與server.js 相同的目錄中創(chuàng)建一個(gè)名為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)建一個(gè)PORT 變量,并將PORT 設(shè)置為監(jiān)聽(tīng)端口8000 。

      PORT=8000

      導(dǎo)入應(yīng)用程序后,在server.js 文件中創(chuàng)建一個(gè)名為port 的常量。將其設(shè)置為你剛剛創(chuàng)建的PORT 變量和一個(gè)默認(rèn)的端口3000

      const port = process.env.PORT || 3000;

      最后,我們將用.listen() 方法設(shè)置應(yīng)用程序在該端口上監(jiān)聽(tīng)。

      app.listen(port, () => {     console.log(`App listening on ${port}`) });

      構(gòu)建路由

      每當(dāng)你訪問(wèn)一個(gè)網(wǎng)頁(yè)或一個(gè)在網(wǎng)絡(luò)上運(yùn)行的應(yīng)用程序時(shí),你都在發(fā)出一個(gè)HTTP請(qǐng)求。服務(wù)器用來(lái)自后臺(tái)或數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行響應(yīng),這就是所謂的HTTP響應(yīng)。

      當(dāng)你在一個(gè)網(wǎng)絡(luò)應(yīng)用程序上創(chuàng)建一個(gè)資源時(shí),你正在調(diào)用POST 請(qǐng)求。同樣地,如果你試圖刪除或更新一個(gè)Web應(yīng)用上的資源,你正在調(diào)用DELETE 、PATCH 、或UPDATE 請(qǐng)求。讓我們建立路由來(lái)處理這些請(qǐng)求。

      在你的工作目錄中創(chuàng)建一個(gè)名為routes 的文件夾,并在其中創(chuàng)建一個(gè)名為analyticsRoute.js 的文件。RequireanalyticsRoute.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)建一個(gè)名為controllers 的文件夾。

      我們的API將使用用戶提供的IP地址和坐標(biāo)來(lái)計(jì)算距離和位置。我們的請(qǐng)求需要接受這些信息和來(lái)自用戶的請(qǐng)求。

      我們將使用一個(gè)POST 請(qǐng)求,因?yàn)橛脩粼?code>req.body 。為了保存這些信息,我們需要在控制器中require 一個(gè)fs 模塊(文件系統(tǒng))。

      處理POST 的請(qǐng)求

      controllers 文件夾中創(chuàng)建一個(gè)名為storeController.js 的文件。在storeController.js 文件中,我們需要導(dǎo)入fs 模塊和fsPromises.readFile() 方法來(lái)處理返回的promise ,也就是用戶的IP地址和坐標(biāo)。

      要安裝fs 模塊,在你的工作目錄中打開(kāi)你的終端,運(yùn)行以下命令。

      npm i fs --save

      在你的文件頂部輸入以下代碼。

      const fsp = require('fs').promises; const fs = require('fs');

      接下來(lái),我們將創(chuàng)建一個(gè)控制器,處理我們的POST 請(qǐng)求的路由。我們將使用exports 關(guān)鍵字并創(chuàng)建一個(gè)接受三個(gè)參數(shù)的異步中間件函數(shù)。

      • req: 代表請(qǐng)求對(duì)象
      • res: 代表響應(yīng)對(duì)象
      • next: 函數(shù)在中間件輸出后立即被調(diào)用。
      postAnalytics = async(req, res, next) => {}

      現(xiàn)在,我們將把req.body 中的數(shù)據(jù)對(duì)象的屬性保存到reportAnalytics 數(shù)組中。我們將設(shè)置一個(gè)Date() 對(duì)象,將任何數(shù)據(jù)的創(chuàng)建日期保存在一個(gè)createdAt 關(guān)鍵中。

      reportAnalytics.push({...req.body, createdAt: new Date()});

      我們將創(chuàng)建一個(gè)名為storeAnalytics.json 的文件,使用JSON.stringify() ,將我們的reportAnalytics 數(shù)組的內(nèi)容保存為一個(gè)字符串。

       await fsp.writeFile(`${__dirname}/storeAnalytics.json`, JSON.stringify(reportAnalytics));

      當(dāng)用戶提出POST 要求時(shí),我們需要檢查storeAnalytics.json 文件是否存在。如果該文件存在,我們需要讀取該文件并保存輸出。

      輸出包含一個(gè)名為reportFile 的常量,它存儲(chǔ)了被讀取的文件內(nèi)容。在reportFile ,使用JSON.parse ,將文件的內(nèi)容轉(zhuǎn)換為一個(gè)JavaScript對(duì)象。

      // 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é)果。接下來(lái),我們用(${__dirname}/storeAnalytics.json 來(lái)指定我們要讀取的文件的路徑。我們將編碼格式設(shè)置為utf-8 ,這將把從文件中讀取的內(nèi)容轉(zhuǎn)換為一個(gè)字符串。

      JSON.parse()reportFile 轉(zhuǎn)換為JavaScript對(duì)象,并將其存儲(chǔ)在reportAnalytics 數(shù)組中。else 語(yǔ)句塊中的代碼只有在文件不存在時(shí)才會(huì)運(yùn)行。最后,我們使用了return 語(yǔ)句,因?yàn)槲覀兿朐诖a運(yùn)行后停止函數(shù)的執(zhí)行。

      如果文件被成功讀取、創(chuàng)建并保存在storeAnalytics.json ,我們需要發(fā)送一個(gè)響應(yīng)。我們將使用響應(yīng)對(duì)象(res) ,它是我們的異步postAnalytics 函數(shù)的第二個(gè)參數(shù)。

          res.status(201).json({         status: 'success',         data: {             message: 'IP and Coordinates successfully taken'         }     })

      我們將用一個(gè)狀態(tài)success 和數(shù)據(jù)信息IP and Coordinates successfully taken 來(lái)響應(yīng)。

      你的storeController.js 文件應(yīng)該看起來(lái)像下面的屏幕截圖。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      處理GET 的請(qǐng)求

      我們需要?jiǎng)?chuàng)建另一個(gè)控制器文件來(lái)處理我們的GET 請(qǐng)求。當(dāng)用戶向API發(fā)出GET 請(qǐng)求時(shí),我們將根據(jù)他們的IP地址和坐標(biāo)來(lái)計(jì)算他們的位置。

      controllers 文件夾中創(chuàng)建一個(gè)名為fetchController.js 的文件。fsstoreController.js 文件中,我們需要require 模塊和fsPromises.readFile() 方法來(lái)處理返回的promise 。

      const fsp = require('fs').promises; const fs = require('fs');

      讓我們創(chuàng)建控制器來(lái)處理我們對(duì)GET 請(qǐng)求的路由。我們將使用類(lèi)似的中間件函數(shù)和參數(shù)來(lái)處理上面的POST 請(qǐng)求。

         exports.getAnalytics = async(req, res, next) => {}

      getAnalytics 中間件中,輸入以下代碼,從請(qǐng)求的查詢中獲得IP地址。

           const { ip } = req.query;

      現(xiàn)在,創(chuàng)建一個(gè)空數(shù)組,用來(lái)存儲(chǔ)req.body 的內(nèi)容。

           let reportAnalytics = [];

      正如我們之前所做的,我們需要檢查storeAnalytics.json 文件是否存在。如果文件存在,我們將在reportFile 上使用JSON.parse ,將文件內(nèi)容轉(zhuǎn)換為一個(gè)JavaScript對(duì)象。

      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)。任何時(shí)候用戶請(qǐng)求根據(jù)提供的坐標(biāo)計(jì)算地理位置,IP地址將以查詢的形式包含在請(qǐng)求中。

      現(xiàn)在我們已經(jīng)從req.query 對(duì)象中得到了IP地址,我們可以編寫(xiě)代碼來(lái)檢查req.query 對(duì)象中提供的IP地址是否與存儲(chǔ)在storeAnalytics.json 文件中的IP地址相同。

         for (let i=0; i<reportAnalytics.length; i++) {         if (reportAnalytics[i].ip !== ip) {            return ('No Coordinates found with that IP');         };     }

      在上面的代碼中,我們使用forloop 來(lái)循環(huán)瀏覽reportAnalytics 數(shù)組。我們將變量i ,代表當(dāng)前元素在reportAnalytics 數(shù)組中的索引,初始化為0 。如果i小于reportAnalytics 數(shù)組的長(zhǎng)度,我們將其遞增。

      接下來(lái),我們檢查reportAnalytics 數(shù)組的IP地址屬性是否等于req.query 中提供的IP地址。

      讓我們計(jì)算一下只在最后一小時(shí)內(nèi)存儲(chǔ)的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)建了一個(gè)名為hourAgo 的常量,并將其設(shè)置為一個(gè)Date 對(duì)象。我們使用setHours() 方法將hourAgo 設(shè)置為最后一個(gè)小時(shí)的getHours()-1

      當(dāng)reportAnalytics 文件中的當(dāng)前IP地址等同于或等于req.query 中傳遞的IP地址時(shí),意味著數(shù)據(jù)是在最后一小時(shí)內(nèi)創(chuàng)建的,getReport 創(chuàng)建一個(gè)常量,設(shè)置為一個(gè)新的數(shù)組。

      創(chuàng)建一個(gè)名為coordinatesArray 的常量,它將只存儲(chǔ)已經(jīng)保存在getReport 數(shù)組中的坐標(biāo)。

      const coordinatesArray = getReport.map(element => element.coordinates)

      接下來(lái),我們需要用坐標(biāo)計(jì)算出位置。我們需要遍歷coordinatesArray ,通過(guò)傳入保存為坐標(biāo)的兩個(gè)值來(lái)計(jì)算位置。

          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 代表從兩個(gè)坐標(biāo)計(jì)算出來(lái)的總距離。為了遍歷coordinatesArray ,我們需要初始化我們的計(jì)算結(jié)果。將totalLength 設(shè)置為零,初始化總距離。

      第二行包含我們使用的迭代代碼forloop 。我們用let i=0 來(lái)初始化i 變量。i 變量代表當(dāng)前元素在coordinatesArray 的索引。

      i<coordinatesArray.length 設(shè)置迭代的條件,只有當(dāng)當(dāng)前元素的索引小于coordinatesArray 的長(zhǎng)度時(shí)才運(yùn)行。接下來(lái),我們?cè)诘性黾赢?dāng)前元素的索引,以移動(dòng)到下一個(gè)元素,i++

      接下來(lái),我們將檢查當(dāng)前元素的索引是否等于數(shù)組中最后一個(gè)元素的編號(hào)。然后,我們暫停迭代代碼的執(zhí)行,用break 關(guān)鍵字移動(dòng)到下一個(gè)。

      最后,我們創(chuàng)建一個(gè)名為calculateDistance 的函數(shù),接受兩個(gè)參數(shù),即第一和第二坐標(biāo)值(經(jīng)度和緯度)。我們將在另一個(gè)模塊中創(chuàng)建calculateDistance ,并將其導(dǎo)出到fetchController.js 文件中,然后我們將最終結(jié)果保存在我們初始化的totalLength 變量中。

      注意,每個(gè)請(qǐng)求都需要一個(gè)響應(yīng)。我們將用一個(gè)200statusCode 和一個(gè)包含我們將計(jì)算的距離值的JSON來(lái)響應(yīng)。只有在代碼成功的情況下才會(huì)顯示響應(yīng)。

           res.status(200).json({distance: totalLength})

      你的fetchController.js 文件應(yīng)該看起來(lái)像下面兩個(gè)代碼塊。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      fetchController.js文件

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      fetchController.js文件的續(xù)篇

      建立calculateDistance 函數(shù)

      在你的工作目錄中,創(chuàng)建一個(gè)名為utilities 的新文件夾,在里面創(chuàng)建一個(gè)名為calculateDistance.js 的文件。打開(kāi)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)建一個(gè)名為calculateDistance 的函數(shù),它接受兩個(gè)參數(shù):coordinate1coordinate2 。它使用下面的方程式。

      • Math.sqrt: 數(shù)學(xué)中的平方根
      • Math.pow :將一個(gè)數(shù)字提高到一個(gè)冪值
      • Number(): 將一個(gè)值轉(zhuǎn)換為一個(gè)數(shù)字
      • coordinate1.x :第一個(gè)坐標(biāo)(經(jīng)度)的第二個(gè)值
      • coordinate2.x :第一個(gè)坐標(biāo)的第一個(gè)值(經(jīng)度)。
      • coordinate1.y :第二個(gè)坐標(biāo)的第二個(gè)值(緯度)。
      • coordinate2.y :第二個(gè)坐標(biāo)的第一個(gè)值(緯度)。

      現(xiàn)在我們已經(jīng)創(chuàng)建了calculateDistance 函數(shù),我們需要將該函數(shù)require 到我們fetchController.js 文件的代碼中。在fs 模塊之后添加下面的代碼。

      const calculateDistance = require('../utilities/calculateDistance');

      實(shí)現(xiàn)錯(cuò)誤處理

      實(shí)現(xiàn)錯(cuò)誤處理是很重要的,以防止我們的代碼失敗或某個(gè)特定的實(shí)現(xiàn)沒(méi)有按照設(shè)計(jì)的方式工作。我們將在開(kāi)發(fā)和生產(chǎn)中添加錯(cuò)誤處理。

      打開(kāi)你的config.env 文件,運(yùn)行NODE_ENV=development ,將環(huán)境設(shè)置為開(kāi)發(fā)。

      在你的controllers 文件夾中,創(chuàng)建一個(gè)名為errorController.js 的新文件。下面的代碼片斷創(chuàng)建了一個(gè)名為sendErrorDev 的函數(shù),以處理在開(kāi)發(fā)環(huán)境中遇到的錯(cuò)誤。

      const sendErrorDev = (err, res) => {     res.status(err.statusCode).json({         status: err.status,         error: err,         message: err.message,         stack: err.stack,     }); }

      我們將創(chuàng)建一個(gè)名為sendErrorDev 的函數(shù),它接受兩個(gè)參數(shù),err 表示錯(cuò)誤,res 表示響應(yīng)。response.status 接收錯(cuò)誤的statusCode ,并以JSON數(shù)據(jù)進(jìn)行響應(yīng)。

      此外,我們將創(chuàng)建一個(gè)名為sendErrorProd 的函數(shù),它將處理API在生產(chǎn)環(huán)境中遇到的錯(cuò)誤。

      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)建一個(gè)名為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)建一個(gè)名為AppError 的類(lèi),它擴(kuò)展了Error 對(duì)象。

      然后,我們將創(chuàng)建一個(gè)構(gòu)造函數(shù),它將初始化該類(lèi)的對(duì)象。它接受兩個(gè)參數(shù),叫做messagestatusCode 。super 方法用一個(gè)參數(shù)調(diào)用構(gòu)造函數(shù),將其傳入message ,并獲得對(duì)構(gòu)造函數(shù)的屬性和方法的訪問(wèn)。

      接下來(lái),我們將構(gòu)造函數(shù)的statusCode 屬性設(shè)置為statusCode 。我們將構(gòu)造函數(shù)的status 屬性設(shè)置為任何以4 開(kāi)始的statusCode ,例如,將404 statusCode 設(shè)置為failerror 。

      創(chuàng)建另一個(gè)名為catchAsync.js 的文件,并在其中添加以下代碼。

      module.exports = fn => {     return (req, res, next) => {         fn(req, res, next).catch(next);     } }

      在控制器文件中添加錯(cuò)誤處理

      Require appError.js 文件和catchAsync.js 文件在你的storeController.jsfetchController.js 文件中。將這兩條導(dǎo)入語(yǔ)句放在兩個(gè)文件中的代碼頂部。

      const catchAsync = require('../utilities/catchAsync'); const AppError = require('../utilities/appError');

      storeController.jsfetchController.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) => {...}

      接下來(lái),在你的fetchController.js 文件中,運(yùn)行AppError 類(lèi)。

         for (let i=0; i<reportAnalytics.length; i++) {         if (reportAnalytics[i].ip !== ip) {            return next(new AppError('No Coordinates found with that IP', 404));         };     }

      接下來(lái),在你的storeController.js 文件中運(yùn)行AppError 類(lèi)。

         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.jsfetchController.js 文件中的代碼應(yīng)該看起來(lái)像下面的截圖。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      storeController.js文件的屏幕截圖

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      fetchController.js文件第1-32行

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      fetchController.js文件第33-37行

      設(shè)置驗(yàn)證

      我們需要驗(yàn)證在req.body ,其中包括IP地址和坐標(biāo)的數(shù)據(jù),是正確的,而且格式正確。坐標(biāo)應(yīng)該至少有兩個(gè)值,代表經(jīng)度和緯度。

      utilities 文件夾中,創(chuàng)建一個(gè)名為Validation 的新文件夾。在Validation 文件夾中,創(chuàng)建一個(gè)名為schema.js 的文件。schema.js 文件將包含req.body 中提供的任何數(shù)據(jù)的所需格式。我們將使用 [joi](https://www.npmjs.com/package/joi)驗(yàn)證器。

      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 驗(yàn)證器,用它來(lái)創(chuàng)建我們的模式。然后,我們將IP地址設(shè)置為總是一個(gè)字符串,并通過(guò)在請(qǐng)求體中要求它來(lái)驗(yàn)證IP地址。

      我們將坐標(biāo)設(shè)置為object 。我們將代表經(jīng)度和緯度值的xy 值都設(shè)置為數(shù)字,并將其require ,以便我們的代碼運(yùn)行。最后,我們導(dǎo)出了模式。

      在驗(yàn)證器文件夾中,創(chuàng)建另一個(gè)名為validateIP.js 的文件。在里面,我們將編寫(xiě)代碼來(lái)驗(yàn)證IP地址,使用 [is-ip](https://www.npmjs.com/package/is-ip)npm包。讓我們把這個(gè)包導(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安裝必要的依賴項(xiàng)。

      npm install body-parser cors dotenv express fs is-ip joi morgan ndb nodemon

      你的app.js 文件應(yīng)該看起來(lái)像下面的屏幕截圖。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      app.js文件

      在你的package.json 文件中的scripts 部分下,添加以下代碼片段。

      "start:dev": "node server.js",     "debug": "ndb server.js"

      你的package.json 文件應(yīng)該看起來(lái)像下面的截圖。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      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)在,讓我們測(cè)試一下我們的代碼,以確保它的工作。

      測(cè)試API

      我們將使用Postman來(lái)測(cè)試我們的API。讓我們啟動(dòng)我們的API以確保它在我們的終端中運(yùn)行。

      node server.js

      你會(huì)在你的終端看到以下輸出。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      終端

      我們的API托管在Heroku上,它的最終輸出應(yīng)該看起來(lái)像下面的輸出。

      一文詳解如何在Node中構(gòu)建一個(gè)輕量級(jí)的位置分析報(bào)告服務(wù)API

      你可以自己在托管的文檔中測(cè)試這個(gè)API

      https://documenter.getpostman.com/view/13856921/TzXumeXS

      結(jié)論

      位置分析是企業(yè)的一個(gè)偉大工具。位置信息可以讓公司更好地服務(wù)于潛在客戶和現(xiàn)有客戶。

      在本教程中,我們學(xué)會(huì)了建立一個(gè)工具,以IP地址和坐標(biāo)的形式獲取位置信息并計(jì)算出距離。我們?cè)贜ode.js中設(shè)置了我們的文件結(jié)構(gòu),建立了處理GETPOST 請(qǐng)求的路由,添加了錯(cuò)誤處理,最后測(cè)試了我們的應(yīng)用程序。

      你可以使用本教程中所學(xué)到的信息來(lái)建立你自己的位置報(bào)告API,你可以根據(jù)自己的業(yè)務(wù)需求進(jìn)行定制。

      The postBuild a location analytics reporting API in Node.jsappeared first onLogRocket Blog.

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)