赞
踩
基于 nodejs 平台,快速、开放、极简的 Web 开发框架。
官方有脚手架程序express-generator,可以快速搭建express的程序。
如果需要安装,建议全局安装:
npm install express-generator -g
使用express-generator搭建:
- express -h
- -h, --help 输出使用方法
- --version 输出版本号
- -e, --ejs 添加对 ejs 模板引擎的支持
- --hbs 添加对 handlebars 模板引擎的支持
- --pug 添加对 pug 模板引擎的支持
- -H, --hogan 添加对 hogan.js 模板引擎的支持
- --no-view 创建不带视图引擎的项目
- -v, --view <engine> 添加对视图引擎(view) <engine> 的支持 (ejs|hbs|hjs|jade|pug|twig|vash) (默认是 jade 模板引擎)
- -c, --css <engine> 添加样式表引擎 <engine> 的支持 (less|stylus|compass|sass) (默认是普通的 css 文件)
- --git 添加 .gitignore
- -f, --force 强制在非空目录下创建
搭建没有模板的项目:
express <项目名称> --no-view
自动创建目录和基本文件,但是不包含依赖包。
安装依赖包:
npm install
执行:
- npm run start
- node ./bin/www
nodemon
是一个适用于开发阶段的辅助工具,它能够自动检测文件(js、json)变化,自动重启项目。
安装
npm install nodemon -g
使用,只要用nodemon替代node就可以。
例如,启动express项目:
- 使用,只要用nodemon替代node就可以。
-
- 例如,启动express项目:
pm2
是重量级的辅助工具,除了具有nodemon的特性之外,还具有自动多线程、负载均衡、日志等等.......
安装:
npm install pm2 -g
启动项目:
pm2 start ./bin/www
查看所有管理中的项目列表:
pm2 list
操作项目:
- 启动一个项目
- pm2 start <id>
- 启动所有项目
- pm2 start all
-
-
- 停止一个项目
- pm2 stop <id>
- 停止所有项目
- pm2 stop all
-
- 重启一个项目
- pm2 restart <id>
- 重启所有项目
- pm2 restart all
-
- 在pm2管理器中删除某个项目
- pm2 delete <id>
- 清除所有项目
- pm2 delete all
启用监控:
pm2 start ./bin/www --watch
打开实时监控画面:
pm2 monit
创建项目目录,并执行初始化命令:
npm init -y
建立主文件(index.js);
安装express到项目中:
npm install express
在index.js中引入express;
const express = require('express');
创建一个express实例:
const app = express();
创建第一个接口(api):
- app.get('/', function (req, res, next) {
- res.send('你好世界!!!');
- })
当用户访问网站根目录时,返回字符串。
最终启动服务器:
- const port = 80;
- app.listen(port, function () {
- console.log('服务器启动,监听在' + port + '端口')
- })
指定静态路径(网站根):
- app.use(
- express.static('./public')
- )
要注意顺序问题,一般情况下,静态路径的指定要在路由之前:
- app.use(
- express.static('./public')
- )
-
-
- app.get('/index.html', function (req, res, next) {
- res.send('你好!!!');
- })
中间键是指,匹配到路径后要做事情的函数:
- app.use('/admin',function(req.res,next){
- next();
- })
app.use(路径,回调函数);
路径省略或为'*',表示匹配任何路径。
- app.use(function(req.res,next){
- next();
- })
- app.use('*',function(req.res,next){
- next();
- })
回调函数中next表示继续向下匹配。
中间件用app调用,全局中间键,还可以在路由中使用,路由中间键
建立路由对象
const router = express.Router();
让express实例使用路由:
app.use('/users', router);
当用户请求地址是已/users开头的,则被router对象接收。
为router设置处理api:
- router.get('/abc',function(req,res){
- res.send('135');
- })
表示当用户访问 http://127.0.0.1/users/abc ,向用户返回135。
通常,我们使用模块化的方式将不同的路由分别建立:
- //在routers文件夹下建立indexRouter.js文件
- const express = require('express');
- const router = express.Router();
-
- router.get('/abc', function (req, res) {
- res.send('135')
- })
- module.exports = router;
我们在主文件中,引入并使用:
- const indexRouter = require('./routers/indexRouter');
-
- app.use('/users', indexRouter);
实际访问地址是:http://127.0.0.1/users/abc
正则匹配:
'ab?cd' ?匹配前面的字符{0,1} ?前出现的字符0-1次
'ab+cd' + 匹配前面的字符{1,} + 前面的字符最少一次
'ab*cd' * 不表示量词,ab和cd中间至少有一个字符,最多不限,字符可以是任意字符。
‘ab(cd)?e’ 小括号表示整体计算,小括号不能出现在开头。
可以直接使用正则表达式来匹配:
router.get(/abc$/,function(req,res){});
动态路由匹配:
- router.get('/class/:classid/news/:newsid', function (req, res, next) {
- res.send(`classid:${req.params.classid} , newsid:${req.params.newsid}`)
- });
res.send() 通用方法,会根据参数类型自动设置返回头。
res.download() 参数是url,向客户端返回需要下载的文件。
res.end() 用来告诉客户端,当前访问已经结束。
res.json() 向客户端返回json类型的数据。
res.jsonp()向客户端以jsonp形式发送数据
res.redirect() 重定向
res.sendFile() 发送文件到浏览器(浏览器会解析)
res.sendStatus() 发送状态码
postman是一个专用于测试服务器api接口的程序。
Postmanhttps://www.postman.com/
动态路由传参:
- //访问地址是http://127.0.0.1/api/1/2/3
- router.get('/api/:a/:b/:c',function(req,res){
- const {a,b,c} = req.params;
- })
请求头传参:
url ?a=1&b=2
- //请求的地址是http://127.0.0.1/api?a=1&b=2&c=3
- router.get('/api',function(req,res){
- const {a,b,c} = req.query;
- })
请求体传参:
- //请求的地址是http://127.0.0.1/api/123?x=1&y=2
- router.get('/api/:p',function(req,res){
- const {p} = req.params
- const {x,y} = req.query;
- const {a,b,c} = req.body;
- })
crypto
crypto用来做加密的操作,可以使用md5、sha1等等很多方式进行加密
安装
npm install crypto
项目用,安装到项目(不安装到全局)。
使用:
- const crypto = require('crypto');
-
- //每个实例只能输出一次;
- const jiami = crypto.createHash('sha1');
- jiami.update('123123');
- //输出16进制的密文
- jiami.digest('hex')
multer
处理formData数据(multipart/form-data),用于上传文件。
安装
npm install multer
使用时,先注册:
const multer = require('multer');
生成实例并配置:
Multer 接受一个 options 对象,其中最基本的是 dest 属性,这将告诉 Multer 将上传文件保存在哪。如果你省略 options 对象,这些文件将保存在内存中,永远不会写入磁盘。
- const upload = multer({
- dest: 'upload/'
- })
-
- router.post('/upload', upload.single('file'), function (req, res) {
- res.json(req.file)
- })
multer不会自动生成目录,需要我们手动创建。
如果你想在上传时进行更多的控制,你可以使用 storage 选项替代 dest。Multer 具有 DiskStorage 和 MemoryStorage 两个存储引擎; 另外还可以从第三方获得更多可用的引擎。
- const storage = multer.diskStorage({
- destination: function (req, file, cb) {
- cb(null, '/tmp/my-uploads')
- },
- filename: function (req, file, cb) {
- cb(null, file.fieldname + '-' + Date.now())
- }
- })
-
- const upload = multer({ storage: storage })
destination:表示文件上传的目录,它可以是一个字符串(目录会自动创建)或函数(目录不会自动创建)。
filename:表示修改后的文件名,需要完整的文件名。
可以限制文件尺寸:
- const upload = multer({
- storage: storage,
- limits: { fileSize: maxSize }
- })
maxSize为字节单位。
如果上传的为多文件:
- app.post('/upload', upload.array('files', 12), function (req, res, next) {
- // req.files 是 `files` 文件数组的信息
- // req.body 将具有文本域数据,如果存在的话
- })
如果上传的表单元素不止一个,可以使用:
- const cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
- app.post('/upload', cpUpload, function (req, res, next) {
- // req.files 是一个对象 (String -> Array) 键是文件名,值是文件数组
- //
- // 例如:
- // req.files['avatar'][0] -> File
- // req.files['gallery'] -> Array
- //
- // req.body 将具有文本域数据,如果存在的话
- })
如果你需要处理一个只有文本域的表单,你应当使用 .none()
:
- app.post('/profile', upload.none(), function (req, res, next) {
- // req.body 包含文本域
- })
jsonwebtoken和express-jwt
登录状态保持,早期使用的方法是session:
当用户第一次访问网站时,网站在内存中生成一个session空间,并返回session-id(内存地址),内存地址写入客户端的cookie中。
弊端:如果客户端关闭cookie功能则无法保持登录状态。多个服务器之间无法共享session。
jsonwebtoken用于生成JWT字符串
express-jwt
用于将JWT字符串解析还原成JSON对象
安装:
npm install jsonwebtoken express-jwt
导入:
- const jwt = require('jsonwebtoken')
- const expressJWT = require('express-jwt')
定义秘钥:
const secretKey = 'hello';
在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并发送给客户端
const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
客户端收到后存储,在请求需要登录后才能访问的url中加入token:
xhr.setRequestHeader('Authorization','Bearer '+token);
服务器通过express-jwt组件来验证,可以全局验证(注册到全局中间键),也可以单独对一个或几个api做验证。
api做验证时:
- const { expressjwt } = require('express-jwt');
-
- router.get(
- '/abc',
- expressjwt({
- secret: 'key',
- algorithms: ['HS256']
- }
- ),
- function (req, res, next) {
- res.json({
- username: req.auth.username
- })
- });
1、路由中间键:
- const { expressjwt } = require('express-jwt');
-
- app.use(expressjwt({
- secret: 'key',//密钥
- algorithms: ['HS256']//jwt的加密算法
-
- }).unless({ path: ['/users/login', /^\/images/] }))
secret:解密秘钥(与加密秘钥相同)。
express-jwt会自动将解密后的内容放入req.auth 。
如果解密失败,则会返回一个403错误。
登录:
判断是否登录成功:jsonwebtoken.sign()生成token。返回给客户端。客户端保存token。
通常,当token验证不通过时,客户端需要得到一个明确的指示,而不是一个简单的错误提示。
我们使用自定义中间键来拦截token错误,固定向客户端返回401错误。
- app.use(function (err, req, res, next) {
- if (err.name === "UnauthorizedError") {
- res.status(401).send("invalid token...");
- } else {
- next(err);
- }
- });
app.js的全局中间键后。
通常与全局中间键写在一起
- app.use(expressjwt({
- secret: 'key',//密钥
- algorithms: ['HS256']//jwt的加密算法
-
- })
- //排除,token验证时,排除'/users/login', '/users/reg'路由地址
- .unless({ path: ['/users/login', '/users/reg'] }));
- //拦截token错误,固定向客户端返回401错误,错误的内容可以自己定制。
- app.use(function (err, req, res, next) {
- if (err.name === "UnauthorizedError") {
- res.status(401).send("invalid token...");
- } else {
- next(err);
- }
- });
用户登录成功后,需要保持登录状态。需要在服务端及客户端都记录一些数据来表示处于已登录状态。
http协议是短链接,访问结束后,访问状态消失,下次访问服务器时,服务器会将客户端当做全新的来看待。
曾经采用的解决方案:
cookie(session)方案
session(会话),application(应用)
会话状态,当我们访问服务器时,服务器会为我们本次访问单独建立一个作用域,访问结束(关掉与服务器的所有连接)时,作用域消失。例如:当我们要访问某个网站时,第一次打开网站的任意一个网页(请求)时,产生本次访问的会话状态,当前访问不结束,再次访问时,与上次的会话状态共享。直到所有的访问全部结束,会话状态结束。
登录成功时,服务器产生一个session,每个session都有一个独立的sessionID。服务器将这个sessionID和登录状态一起存储在客户端的cookie中。当客户端再次访问服务器时,服务器会尝试读取客户端的sessionID,看看在服务器中,这个sessionID对应的session是否还存在,如果不存在了,则表示登录超时,如果还存在,进一步读取登录状态,来判断是否还处于登陆中。
这种判断过程,对于单服务器比较完美,还要看客户端是否禁用了cookie。
改进的方案:token方案
1、当用户登录成功后,服务器生成一个加密的字符串,这个字符串包含三部分内容:第一部分是存储加密头信息、第二部分存储过期时间、第三部分是存储我们需要额外存储的信息。独一无二的。服务器对应的也会存储秘钥用于解密。
2、服务器将这个token发送给客户端,客户端存储这个token。
3、当客户端需要再次访问服务器时,在参数中将这个token发送给服务器。
4、服务器判断当前请求有没有附加token信息,如果没有,那就表示没有登录,如果有,则用秘钥解密token,得到过期时间,看当前时间是否处于过期时间,处于过期时间内则表示还处于登录状态,超出过期时间则表示登录超时。
在需要登录后才能访问的api中做登录验证。
客户端在发送请求(get、post)时,需要携带token(请求头)。
服务器接收到请求时,用express-jwt去获取客户端携带的token,解密(还原)。
是否可以还原,如果可以还原再判断过期时间。都通过则将加密的数据保存在req.auth中,next();
如果任何一步出错了,则不再继续,返回401错误。
验证时:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。