이 기사에서는 실제 경험을 공유하고Node에서 위치 분석 보고서 API를 구축하는 방법을 소개합니다. 이 튜토리얼을 마치면 Node.js의 오류 처리 및 좋은 파일 구조에 대해 더 잘 이해할 수 있을 것입니다. js. 좋은 이해입니다. 모두에게 도움이 되기를 바랍니다!
위도와 경도로 정의된 위치를 다른 데이터와 결합하여 비즈니스에 대한 통찰력을 생성할 수 있으며 이를 위치 분석이라고 합니다.
전 세계적으로 운영되는 기업은 전체 가치 사슬에서 위치 분석을 사용하여 사용자를 타겟팅하고, 서비스를 제공하고, 타겟 광고를 실행합니다. 소셜 미디어와 모바일 장치의 등장으로 위치 분석의 사용이 전 세계적으로 증가했습니다.
이 튜토리얼에서는Node.js에서 간단한 위치 분석 보고 서비스 API를 구축하는 방법을 알아봅니다. 이 튜토리얼이 끝나면 자신의 프로젝트에 대해 이러한 유형의 API를 구축할 수 있게 됩니다. 또한 Node.js의 오류 처리 및 좋은 파일 구조에 대해 더 잘 이해할 수 있습니다.
시작하겠습니다!
이 튜토리얼을 진행하려면 다음이 필요합니다.
먼저 파일 구조를 설정해야 합니다. 터미널을 열고 프로젝트의 모든 파일을 저장할 새 디렉터리를 만듭니다. 터미널에서 다음 명령을 입력하고 그 뒤에 폴더 이름lars
를 입력하세요.lars
。
mkdir lars
在VS代码编辑器中打开lars
工作目录。
code .
你会看到你的VS Code窗口打开。
Visual Studio Code 窗口
通过在Visual Studio中打开你的终端并运行npm init -y
,初始化工作目录。
如果你想在VS Code之外的操作系统的终端中运行这个命令,请导航到lars
目录并运行下面的命令。
npm init -y
上面的代码自动生成了package.json
文件。
VS Code显示创建的package.json文件
在本教程中,我们将使用Express作为一个依赖项。通过运行下面的命令来安装Express。
npm install express --save
将Express作为依赖关系安装的命令
安装完Express后,你会注意到一个node_modules
文件夹被创建了。为了确认你已经安装了Express,请检查你的package.json
文件,你会看到Express作为一个依赖项被安装。
node_modules文件夹被创建,Express被添加到package.json中。
我们需要将Express导入我们的应用程序,因为它是一个npm模块。在与你的package.json
文件相同的目录下创建一个名为app.js
的新文件。
VS代码窗口的截图显示app.js已经创建。
在你的app.js
文件中,通过运行下面的代码require
Express。
const express = require('express');
导入Express
现在,调用Express来创建你的应用、路由和你的应用要运行的端口。
const app = express();
Node.js实现了模块化,这意味着它将你的应用分成模块,或各种文件,并导出每个文件。我们将使用export
关键字导出app
。
module.exports = app;
app.js文件
接下来,在与app.js
文件相同的目录下创建另一个名为server.js
的文件。Require
将app.js
文件导入server.js
文件。
const app = require('./app');
在与server.js
相同的目录中创建一个名为config.env
的文件。config.env
文件将包含我们的应用程序需要的所有[process.env](https://nodejs.org/dist/latest-v8.x/docs/api/process.html)
我们的应用程序需要的所有密钥。在config.env
文件中,创建一个PORT
变量,并将PORT
设置为监听端口8000
PORT=8000
lars
작업 디렉터리를 엽니다.
const port = process.env.PORT || 3000;
npm init -y
를 실행하여 작업 디렉터리를 초기화하세요. VS Code가 아닌 운영 체제의 터미널에서 이 명령을 실행하려면
lars
디렉터리로 이동하여 아래 명령을 실행하세요.
app.listen(port, () => { console.log(`App listening on ${port}`) });
package.json
파일을 생성합니다.
VS 코드는 생성된 package.json 파일을 보여줍니다. 이 튜토리얼에서는 Express를 종속성으로 사용합니다. 아래 명령을 실행하여 Express를 설치하십시오.
const express = require('express');
node_modules
폴더가 생성되는 것을 확인할 수 있습니다. Express가 설치되어 있는지 확인하려면
package.json
파일을 확인하세요. 그러면 Express가 종속성으로 설치되어 있는 것을 볼 수 있습니다.
node_modules 폴더가 생성되고 package.json에 Express가 추가됩니다. Express는 npm 모듈이므로 애플리케이션으로 가져와야 합니다.
package.json
파일과 동일한 디렉터리에
app.js
라는 새 파일을 만듭니다.
VS 코드 창의 스크린샷은 app.js가 생성되었음을 보여줍니다.
app.js
파일에서 다음 코드를 실행하여
require
를 표현하세요.
const app = require('../app');
const router = express.Router();
export
키워드를 사용하여
app
을 내보냅니다.
module.exports = router;
app.js
파일과 동일한 디렉터리에
server.js
라는 이름의 다른 파일을 만듭니다.
필수
app.js
파일을
server.js
파일로 가져옵니다.
npm i fs --save
server.js
와 동일한 디렉터리에
config.env
라는 파일을 만듭니다.
config.env
파일에는 모든
[process.env](https://nodejs.org/dist/latest-v8.x/docs/api/process .html)<가 포함됩니다. /code>애플리케이션에 필요한 모든 키입니다. config.env
파일에서
PORT
변수를 생성하고
PORT
를 설정하여 포트
8000
에서 수신 대기하도록 합니다.
PORT=8000
로그인 후 복사
로그인 후 복사
导入应用程序后,在server.js
文件中创建一个名为port
的常量。将其设置为你刚刚创建的PORT
变量和一个默认的端口3000
。
const port = process.env.PORT || 3000;
로그인 후 복사
로그인 후 복사
最后,我们将用.listen()
方法设置应用程序在该端口上监听。
app.listen(port, () => { console.log(`App listening on ${port}`) });
로그인 후 복사
로그인 후 복사
构建路由
每当你访问一个网页或一个在网络上运行的应用程序时,你都在发出一个HTTP请求。服务器用来自后台或数据库的数据进行响应,这就是所谓的HTTP响应。
当你在一个网络应用程序上创建一个资源时,你正在调用POST
请求。同样地,如果你试图删除或更新一个Web应用上的资源,你正在调用DELETE
、PATCH
、或UPDATE
请求。让我们建立路由来处理这些请求。
在你的工作目录中创建一个名为routes
的文件夹,并在其中创建一个名为analyticsRoute.js
的文件。Require
在analyticsRoute.js
文件中表达,以设置API的路由。
const express = require('express');
로그인 후 복사
로그인 후 복사
我们还需要从app.js
文件中require
我们的应用程序模块。
const app = require('../app');
로그인 후 복사
로그인 후 복사
然后,我们创建我们的路由。
const router = express.Router();
로그인 후 복사
로그인 후 복사
最后,我们要导出路由器。
module.exports = router;
로그인 후 복사
로그인 후 복사
建立控制器
我们需要为控制器创建文件,将其导入我们的analyticsRoutes
文件。首先,在你的工作目录中创建一个名为controllers
的文件夹。
我们的API将使用用户提供的IP地址和坐标来计算距离和位置。我们的请求需要接受这些信息和来自用户的请求。
我们将使用一个POST
请求,因为用户在req.body
。为了保存这些信息,我们需要在控制器中require
一个fs
模块(文件系统)。
处理POST
的请求
在controllers
文件夹中创建一个名为storeController.js
的文件。在storeController.js
文件中,我们需要导入fs
模块和fsPromises.readFile()
方法来处理返回的promise
,也就是用户的IP地址和坐标。
要安装fs
模块,在你的工作目录中打开你的终端,运行以下命令。
npm i fs --save
로그인 후 복사
로그인 후 복사
在你的文件顶部输入以下代码。
const fsp = require('fs').promises; const fs = require('fs');
로그인 후 복사
로그인 후 복사
接下来,我们将创建一个控制器,处理我们的POST
请求的路由。我们将使用exports
关键字并创建一个接受三个参数的异步中间件函数。
req
: 代表请求对象
res
: 代表响应对象
next
: 函数在中间件输出后立即被调用。
postAnalytics = async(req, res, next) => {}
로그인 후 복사
现在,我们将把req.body
中的数据对象的属性保存到reportAnalytics
数组中。我们将设置一个Date()
对象,将任何数据的创建日期保存在一个createdAt
关键中。
reportAnalytics.push({...req.body, createdAt: new Date()});
로그인 후 복사
我们将创建一个名为storeAnalytics.json
的文件,使用JSON.stringify()
,将我们的reportAnalytics
数组的内容保存为一个字符串。
await fsp.writeFile(`${__dirname}/storeAnalytics.json`, JSON.stringify(reportAnalytics));
로그인 후 복사
当用户提出POST
要求时,我们需要检查storeAnalytics.json
文件是否存在。如果该文件存在,我们需要读取该文件并保存输出。
输出包含一个名为reportFile
的常量,它存储了被读取的文件内容。在reportFile
,使用JSON.parse
,将文件的内容转换为一个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
路径作为其单一参数,并指向我们要检查的文件的位置。
我们将await
关键字与reportFile
,以等待用fsp.readFile()
方法读取文件的结果。接下来,我们用(${__dirname}/storeAnalytics.json
来指定我们要读取的文件的路径。我们将编码格式设置为utf-8
,这将把从文件中读取的内容转换为一个字符串。
JSON.parse()
将reportFile
转换为JavaScript对象,并将其存储在reportAnalytics
数组中。else
语句块中的代码只有在文件不存在时才会运行。最后,我们使用了return
语句,因为我们想在代码运行后停止函数的执行。
如果文件被成功读取、创建并保存在storeAnalytics.json
,我们需要发送一个响应。我们将使用响应对象(res)
,它是我们的异步postAnalytics
函数的第二个参数。
res.status(201).json({ status: 'success', data: { message: 'IP and Coordinates successfully taken' } })
로그인 후 복사
我们将用一个状态success
和数据信息IP and Coordinates successfully taken
来响应。
你的storeController.js
文件应该看起来像下面的屏幕截图。
处理GET
的请求
我们需要创建另一个控制器文件来处理我们的GET
请求。当用户向API发出GET
请求时,我们将根据他们的IP地址和坐标来计算他们的位置。
在controllers
文件夹中创建一个名为fetchController.js
的文件。fs
在storeController.js
文件中,我们需要require
模块和fsPromises.readFile()
方法来处理返回的promise
。
const fsp = require('fs').promises; const fs = require('fs');
로그인 후 복사
로그인 후 복사
让我们创建控制器来处理我们对GET
请求的路由。我们将使用类似的中间件函数和参数来处理上面的POST
请求。
exports.getAnalytics = async(req, res, next) => {}
로그인 후 복사
在getAnalytics
中间件中,输入以下代码,从请求的查询中获得IP地址。
const { ip } = req.query;
로그인 후 복사
现在,创建一个空数组,用来存储req.body
的内容。
let reportAnalytics = [];
로그인 후 복사
正如我们之前所做的,我们需要检查storeAnalytics.json
文件是否存在。如果文件存在,我们将在reportFile
上使用JSON.parse
,将文件内容转换为一个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'); }
로그인 후 복사
现在,我们可以在storeAnalytics.json
文件中保存用户的IP地址和坐标。任何时候用户请求根据提供的坐标计算地理位置,IP地址将以查询的形式包含在请求中。
现在我们已经从req.query
对象中得到了IP地址,我们可以编写代码来检查req.query
对象中提供的IP地址是否与存储在storeAnalytics.json
文件中的IP地址相同。
for (let i=0; i
로그인 후 복사
在上面的代码中,我们使用forloop
来循环浏览reportAnalytics
数组。我们将变量i
,代表当前元素在reportAnalytics
数组中的索引,初始化为0
。如果i小于reportAnalytics
数组的长度,我们将其递增。
接下来,我们检查reportAnalytics
数组的IP地址属性是否等于req.query
中提供的IP地址。
让我们计算一下只在最后一小时内存储的IP地址的位置。
const hourAgo = new Date(); hourAgo.setHours(hourAgo.getHours()-1); const getReport = reportAnalytics.filter(el => el.ip === ip && new Date(el.createdAt) > hourAgo )
로그인 후 복사
在上面的代码块中,我们创建了一个名为hourAgo
的常量,并将其设置为一个Date
对象。我们使用setHours()
方法将hourAgo
设置为最后一个小时的getHours()-1
。
当reportAnalytics
文件中的当前IP地址等同于或等于req.query
中传递的IP地址时,意味着数据是在最后一小时内创建的,getReport
创建一个常量,设置为一个新的数组。
创建一个名为coordinatesArray
的常量,它将只存储已经保存在getReport
数组中的坐标。
const coordinatesArray = getReport.map(element => element.coordinates)
로그인 후 복사
接下来,我们需要用坐标计算出位置。我们需要遍历coordinatesArray
,通过传入保存为坐标的两个值来计算位置。
let totalLength = 0; for (let i=0; i
로그인 후 복사
在上面的代码中,totalLength
代表从两个坐标计算出来的总距离。为了遍历coordinatesArray
,我们需要初始化我们的计算结果。将totalLength
设置为零,初始化总距离。
第二行包含我们使用的迭代代码forloop
。我们用let i=0
来初始化i
变量。i
变量代表当前元素在coordinatesArray
的索引。
i设置迭代的条件,只有当当前元素的索引小于coordinatesArray
的长度时才运行。接下来,我们在迭代中增加当前元素的索引,以移动到下一个元素,i++
。
接下来,我们将检查当前元素的索引是否等于数组中最后一个元素的编号。然后,我们暂停迭代代码的执行,用break
关键字移动到下一个。
最后,我们创建一个名为calculateDistance
的函数,接受两个参数,即第一和第二坐标值(经度和纬度)。我们将在另一个模块中创建calculateDistance
,并将其导出到fetchController.js
文件中,然后我们将最终结果保存在我们初始化的totalLength
变量中。
注意,每个请求都需要一个响应。我们将用一个200
的statusCode
和一个包含我们将计算的距离值的JSON来响应。只有在代码成功的情况下才会显示响应。
res.status(200).json({distance: totalLength})
로그인 후 복사
你的fetchController.js
文件应该看起来像下面两个代码块。
fetchController.js文件
fetchController.js文件的续篇
建立calculateDistance
函数
在你的工作目录中,创建一个名为utilities
的新文件夹,在里面创建一个名为calculateDistance.js
的文件。打开calculateDistance.js
文件,添加以下函数。
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;
로그인 후 복사
在第一行,我们创建一个名为calculateDistance
的函数,它接受两个参数:coordinate1
和coordinate2
。它使用下面的方程式。
Math.sqrt
: 数学中的平方根
Math.pow
:将一个数字提高到一个幂值
Number()
: 将一个值转换为一个数字
coordinate1.x
:第一个坐标(经度)的第二个值
coordinate2.x
:第一个坐标的第一个值(经度)。
coordinate1.y
:第二个坐标的第二个值(纬度)。
coordinate2.y
:第二个坐标的第一个值(纬度)。
现在我们已经创建了calculateDistance
函数,我们需要将该函数require
到我们fetchController.js
文件的代码中。在fs
模块之后添加下面的代码。
const calculateDistance = require('../utilities/calculateDistance');
로그인 후 복사
实现错误处理
实现错误处理是很重要的,以防止我们的代码失败或某个特定的实现没有按照设计的方式工作。我们将在开发和生产中添加错误处理。
打开你的config.env
文件,运行NODE_ENV=development
,将环境设置为开发。
在你的controllers
文件夹中,创建一个名为errorController.js
的新文件。下面的代码片断创建了一个名为sendErrorDev
的函数,以处理在开发环境中遇到的错误。
const sendErrorDev = (err, res) => { res.status(err.statusCode).json({ status: err.status, error: err, message: err.message, stack: err.stack, }); }
로그인 후 복사
我们将创建一个名为sendErrorDev
的函数,它接受两个参数,err
表示错误,res
表示响应。response.status
接收错误的statusCode
,并以JSON数据进行响应。
此外,我们将创建一个名为sendErrorProd
的函数,它将处理API在生产环境中遇到的错误。
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
文件夹中,创建一个名为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;
로그인 후 복사
我们将创建一个名为AppError
的类,它扩展了Error
对象。
然后,我们将创建一个构造函数,它将初始化该类的对象。它接受两个参数,叫做message
和statusCode
。super
方法用一个参数调用构造函数,将其传入message
,并获得对构造函数的属性和方法的访问。
接下来,我们将构造函数的statusCode
属性设置为statusCode
。我们将构造函数的status
属性设置为任何以4
开始的statusCode
,例如,将404 statusCode
设置为fail
或error
。
创建另一个名为catchAsync.js
的文件,并在其中添加以下代码。
module.exports = fn => { return (req, res, next) => { fn(req, res, next).catch(next); } }
로그인 후 복사
在控制器文件中添加错误处理
Require
appError.js
文件和catchAsync.js
文件在你的storeController.js
和fetchController.js
文件中。将这两条导入语句放在两个文件中的代码顶部。
const catchAsync = require('../utilities/catchAsync'); const AppError = require('../utilities/appError');
로그인 후 복사
在storeController.js
和fetchController.js
文件中,用catchAsync()
方法包装你的函数,如下所示。
// For storeController.js file exports.postAnalytics = catchAsync(async(req, res, next) => {...} // For fetchController.js file exports.getAnalytics = catchAsync(async(req, res, next) => {...}
로그인 후 복사
接下来,在你的fetchController.js
文件中,运行AppError
类。
for (let i=0; i
로그인 후 복사
接下来,在你的storeController.js
文件中运行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
文件中的代码应该看起来像下面的截图。
storeController.js文件的屏幕截图
fetchController.js文件第1-32行
fetchController.js文件第33-37行
设置验证
我们需要验证在req.body
,其中包括IP地址和坐标的数据,是正确的,而且格式正确。坐标应该至少有两个值,代表经度和纬度。
在utilities
文件夹中,创建一个名为Validation
的新文件夹。在Validation
文件夹中,创建一个名为schema.js
的文件。schema.js
文件将包含req.body
中提供的任何数据的所需格式。我们将使用[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
验证器,用它来创建我们的模式。然后,我们将IP地址设置为总是一个字符串,并通过在请求体中要求它来验证IP地址。
我们将坐标设置为object
。我们将代表经度和纬度值的x
和y
值都设置为数字,并将其require
,以便我们的代码运行。最后,我们导出了模式。
在验证器文件夹中,创建另一个名为validateIP.js
的文件。在里面,我们将编写代码来验证IP地址,使用[is-ip](https://www.npmjs.com/package/is-ip)
npm包。让我们把这个包导出到我们的代码中。
在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(); }
로그인 후 복사
运行以下命令,为我们的API安装必要的依赖项。
npm install body-parser cors dotenv express fs is-ip joi morgan ndb nodemon
로그인 후 복사
你的app.js
文件应该看起来像下面的屏幕截图。
app.js文件
在你的package.json
文件中的scripts
部分下,添加以下代码片段。
"start:dev": "node server.js", "debug": "ndb server.js"
로그인 후 복사
你的package.json
文件应该看起来像下面的截图。
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;
로그인 후 복사
现在,我们已经完成了我们的位置分析API的构建!现在,让我们测试一下我们的代码,以确保它的工作。
测试API
我们将使用Postman来测试我们的API。让我们启动我们的API以确保它在我们的终端中运行。
node server.js
로그인 후 복사
你会在你的终端看到以下输出。
终端
我们的API托管在Heroku上,它的最终输出应该看起来像下面的输出。
你可以自己在托管的文档中测试这个API。
https://documenter.getpostman.com/view/13856921/TzXumeXS
结论
位置分析是企业的一个伟大工具。位置信息可以让公司更好地服务于潜在客户和现有客户。
이 튜토리얼에서는 IP 주소와 좌표 형태로 위치 정보를 얻고 거리를 계산하는 도구를 만드는 방법을 배웠습니다. Node.js에서 파일 구조를 설정하고,GET
和POST
요청을 처리하기 위한 경로를 설정하고, 오류 처리를 추가하고, 최종적으로 애플리케이션을 테스트했습니다.
이 튜토리얼에서 배운 정보를 사용하여 비즈니스 요구에 맞게 사용자 정의할 수 있는 자체 위치 보고 API를 구축할 수 있습니다.
게시물Build a location Analytics reporter API in Node.js가LogRocket Blog에 먼저 나타났습니다.
노드 관련 지식을 더 보려면nodejs tutorial을 방문하세요!
위 내용은 이 문서에서는 Node.js에서 경량 위치 분석 보고 서비스 API를 구축하는 방법을 자세히 설명합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!