Express是什么
Postman
Express
创建一个入口为app.js的npm初始化环境
安装第四版express
npm i express@4
简单的测试-使用postman
const express = require('express');
const app = express();
//配置router
app.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();
//发json
app.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 server
const 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();
///Middleware
app.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回车错误:修改方法