Express是什么
Postman
下载
API测试工具
可以使用dog api测试
Express
创建一个入口为app.js的npm初始化环境
安装第四版express
npm i express@4
简单的测试-使用postman
const express = require('express');const app = express();//配置routerapp.get('/', (req, res) => {res.status(200).send('hello from server');});const port = 3000;app.listen(port, () => {console.log(`App running on port ${port}...`);});
或者:
const express = require('express');const app = express();//发jsonapp.get('/', (req, res) => {res.status(200).json({massage: 'hello from server', app: 'Natours' });});const port = 3000;app.listen(port, () => {console.log(`App running on port ${port}...`);});
或者
app.post('/',(req,res)=>{res.send('You can post to this endpoint')})
API - REST架构
API是什么
API设计原则
使用不同的http方法而不是设计混乱的的动词 JSON的设计 弱状态设计我们的api
在api中传入一个路由处理器 router handler
实现post和get方法:
const tours = JSON.parse(fs.readFileSync(`${__dirname}/dev-data/data/tours-simple.json`));app.get('/api/v1/tours', (req, res) => {res.status(200).json({//设置api返回的数据格式status: 'success',results: tours.length,data: {tours: tours,},});});app.post('/api/v1/tours', (req, res) => {console.log(req.body);res.send('Done');});
测试:如何在postman传入数据
重整代码:将回调函数分离,将相同路径的路由放到一起
const getAllTour = (req, res) => {res.status(200).json({//设置api返回的数据格式status: 'success',results: tours.length,data: {tours: tours,},});};const getTour = (req, res) => {console.log(req.params);const id = req.params.id * 1; // 转换数字小技巧const tour = tours.find((el) => el.id === id);// if (id > tours.length) {if (!tour) {return res.status(404).json({status: 'fail',massage: 'Invalid ID',});}res.status(200).json({//设置api返回的新数据status: 'success',// results: tours.length,data: {tour: tour,},});};const createTour = (req, res) => {// console.log(req.body);const newId = tours[tours.length - 1].id + 1;const newTour = Object.assign({id: newId }, req.body);tours.push(newTour);fs.writeFile(`${__dirname}/dev-data/data/tours-simple.json`,JSON.stringify(tours),(err) => {res.status(201).json({status: 'success',data: {tour: newTour,},});});};const updateTour = (req, res) => {//略if (req.params.id * 1 > tours.length) {return res.status(404).json({status: 'fail',massage: 'Invalid ID',});}res.status(200).json({status: 'success',data: {tour: '<Updated tour here...>',},});};const deleteTour = (req, res) => {//略if (req.params.id * 1 > tours.length) {return res.status(404).json({status: 'fail',massage: 'Invalid ID',});}//204不返回信息res.status(204).json({status: 'success',data: null,});};// app.get('/api/v1/tours', getAllTour);// //app.get('/api/v1/tours/:id?' 后加问号表示可选// app.get('/api/v1/tours/:id', getTour);// app.post('/api/v1/tours', createTour);//使用patch使每次更新只更新变化的对象// app.patch('/api/v1/tours/:id', updateTour);// app.delete('/api/v1/tours/:id', deleteTour);//指定路由然后链接函数app.route('/api/v1/tours').get(getAllTour).post(createTour);app.route('/api/v1/tours/:id').get(getTour).patch(updateTour).delete(deleteTour);
中间件
处理请求与响应中间的所有函数都是中间件像自定义post,get等是生效在特定网址上的middleware注意中间件是有顺序的,如果在他之前结束了http response那么中间件不会被执行尽可能多的使用中间件,每个中间件只实现一个特定功能自定义一个中间件
app.use((req, res, next) => {console.log('-----Hello from th middleware!!----');next();});app.use((req, res, next) => {req.requestTime = new Date().toISOString();next();});//在请求处理函数中console.log(req.requestTime);
morgan的使用
npm i morgan
可以简单的记录日志
使用中间件多用路由
之前的路由:
app.route('/api/v1/tours').get(getAllTour).post(createTour);app.route('/api/v1/tours/:id').get(getTour).patch(updateTour).delete(deleteTour);app.route('/api/v1/users').get(getAllUsers).post(createUser);app.route('/api/v1/users/:id').get(getUser).patch(updateUser).delete(deleteUser);
改为
//指定路由然后链接函数const userRouter = express.Router();userRouter.route('/').get(getAllUsers).post(createUser);userRouter.route('/:id').get(getUser).patch(updateUser).delete(deleteUser);//中间件的一种,挂载到指定url上--父路线//此时运行到这里,会将路由补全 app.use('/api/v1/users', userRouter);
还是使用中间件进行挂载
分为不同文件
分离路由
每种路由相当于一个功能不同的小应用const express = require('express');。。。路由本体定义//指定路由然后链接函数const router = express.Router();router.route('/').get(getAllUsers).post(createUser);router.route('/:id').get(getUser).patch(updateUser).delete(deleteUser);module.exports = router;
最后在总文件中引入,这样就使得路由与本体分离了
将路由处理器与路由文件分离
创建controler文件夹,放入所有handler,导出模块
const express = require('express');//导入模块const userController = require('../controllers/userController');router.route('/').get(userController.getAllUsers).post(userController.createUser);router.route('/:id').get(userController.getUser).patch(userController.updateUser).delete(userController.deleteUser);module.exports = router;
将与服务器相关的代码放入server.js
const app = require('./app');/start serverconst port = 3000;app.listen(port, () => {console.log(`App running on port ${port}...`);});
此时的app.js
全部都是express的相关内容
const express = require('express');const morgan = require('morgan');const tourRouter = require('./routes/tourRouters');const userRouter = require('./routes/usersRouters');const app = express();///Middlewareapp.use(morgan('dev'));app.use(express.json());app.use((req, res, next) => {console.log('-----Hello from th middleware!!----');next();});app.use((req, res, next) => {req.requestTime = new Date().toISOString();next();});app.use('/api/v1/tours', tourRouter);app.use('/api/v1/users', userRouter);module.exports = app;
ParamMiddlware
使用参数中间件获取id
router.param('id', (res, req, next, val) => {console.log(`Tour id is ${val}`);next();});
优化代码
之前的代码:
if (req.params.id * 1 > tours.length) {return res.status(404).json({status: 'fail',massage: 'Invalid ID',});}
分离这段代码
exports.checkID = (req, res, next, val) => {console.log(`Tour id is ${val}`);if (val * 1 > tours.length) {return res.status(404).json({status: 'fail',massage: 'Invalid ID',});}next();};
使用中间件进行检测
router.param('id', tourController.checkID);
为特定的响应操作添加中间件
只需在post中添加一个新的函数
router.route('/').post(middleWare, tourController.createTour);
浏览器访问静态文件
使用中间件
app.use(express.static(`${__dirname}/public`));
这样当指定的文件无法找到路由定义时,express将自动将根目录设置为public文件夹,后对其进行匹配
环境变量
process对象
process 对象是一个全局变量,提供了有关当前 Node.js进程的信息并对其进行控制
process解析
读取环境变量
默认为开发环境
//express环境console.log(app.get('env'));//node环境console.log(process.env);
设置环境变量
为某环境设置变量,需要在命令前加入环境变量
NODE_ENV=development X=23 nodemon server.js
win此时报错解决方法
npm install --save-dev “cross-env” 模块。修改代码为
cross-env NODE_ENV=development node foo.js。然后你可以运行类似的 npm run build。
或者使用(未测试)
使用文件设置
为所有环境变量创造文件config.env
安装包 npm i dotenv
引入server中(为了使app文件只专注于更改中间件等操作
注意引入文件必须在app的引入之前,否则app内无法获取到环境变量
const dotenv = require('dotenv');dotenv.config({path: './config.env' });console.log(process.env);const app = require('./app');
此时可以根据环境判断要不要进行某些操作
if (process.env.NODE_ENV === 'develepment') {app.use(morgan('dev'));}
ESLint
ESLint 是一个代码检查工具,用来检查你的代码是否符合指定的规范(例如: = 的前后必须有一个空格)。
一般和prettier配合使用
安装插件后运行:
npm i eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-config-airbnb eslint-plugin-node eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react --save-dev–save-dev的作用:当包被下载到新地方,使用npm init,每次安装时会自动安装这些模块
此时将会在文件中自动添加两种配置文件
eslint会将不符合设置的规则的语法进行报错,我们可以个性化修改配置文件避免报错(off/error/warn)
crlf回车错误:修改方法