Express之我的博客后台开发过程

本文是对我的个人网站后台的开发过程记录,项目通过express搭建,数据库是mysql

一、项目创建

这次项目通过express-generator创建:

# install
npm install -g express-generator
# create project
express projectname
# enter
cd projectname
# download dependencies
npm i

以上步骤完成之后,项目目录如下:

├─bin					# start: node ./bin/www
├─node_modules			# dependencies
├─public				# static resources
│  ├─images
│  ├─javascripts
│  └─stylesheets
├─routes				# routes
├─views					# pages
├─app.js				# app
├─package.json			# config
└─package-lock.json		# dependencies collective info

文件分析

./bin/www.js

创建服务器,监听端口,监听服务器errorlistening事件。
这个文件之后没有什么需要修改的地方。

./app.js

创建app,引入路由文件、引入中间件等。

eg.

// create app
var app = express();
// route
var indexRouter = require('./routes/index');
app.use('/', indexRouter);
// middleware
app.use(cookieParser());

后期新建的路由文件、新引入的插件等都要在这里引入。

./routes/index.js
var express = require('express');
var router = express.Router();

/* for request '/' */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

二、数据库操作

在根目录下创建module文件夹,并在其中新建db.js模块作为数据库操作的基类:

/* import mysql */
const mysql = require('mysql');
/* create and export DB */
module.exports = class DB {
	// mysql connection object
	static conn = null;
	// mysql connecting function
	static connection () {
		// create mysql connection object
		DB.conn = mysql.createConnection({
			host: 'localhost',
			user: 'root',
			password: 'password',
			database: 'myblog',
			insecureAuth: true
		});
		// connect
		DB.conn.connect(err => {
			if (err) {
				console.log('Connection failed: ' + err);
			}
		})
	}
	// stop connection
	static end () {
		if (DB.conn != null) {
			DB.conn.end();
		}
	}
	/*
	*  sql query function
	* 	... ...
	*/
	static query (sql) {
		return new Promise( (resolve, reject) => {
			// connect mysql
			this.connection();
			// query
			DB.conn.query(sql, (err, res) => {
				if (err) {
					reject(err);
				} else {
					resolve(res);
				}
			});
			// stop connection
			this.end();
		})
	}
}

连接mysql数据库失败

(一)在测试数据库查询方法时 ,出现以下报错:

Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

解决方法:在你的mysql安装路径下找到bin文件夹并打开,运行cmd,如

C:\mysql\mysql\bin

# 1. login with password
mysql -u root -p
# 2. enter your password
# 3. alter mysql_native_password
alter user 'root'@'localhost' identified with mysql_native_password by 'yourRootPassword';

(二)之后又碰巧忘记root密码,此处推荐一篇博文,可以解决这个问题:
Win10下Mysql8忘记密码,登录及修改Mysql密码

提示:如果操作过程中,输入命令后既不执行也不报错,可以关闭控制台后重新打开一个窗口再输入。

三、登录功能

./module文件夹中新建user.js模块,用来处理和用户相关的操作,如登录、注册等。
因为以上操作涉及对数据库的增删改查,所以需要User继承之前创建的`DB``类。

基础版

/* import DB, create and export User */
module.exports = class User extends require('./db') {
	static login (username, password) {
		return new Promise((resolve, reject) => {
			const sql = `select username, id from users where username=${username}&&password=${password}`;
			this.query(sql).then(res => {
				resolve(res);
			}).catch(err => {
				console.log(err);
			})
		})
	}
}

以上代码只根据用户传入的用户名、密码做了查询,还需要在服务端生成token,返回到客户端。

使用jsonwebtoekn生成token

首先,安装jsonwebtoekn

npm install jsonwebtoken

引入

const jwt = require('jsonwebtoken');

生成

const data = { id: 'u_1234' };
const privateKey = 'hahaha';
const expireTime = { expiresIn: 60 * 60 };  // expire in 1 hour, not mandatory param
// Synchronous Sign with default (HMAC SHA256)
/*
*	@params data
*	@params privateKey
*/
const token = jwt.sign(data, privateKey, expireTime )

以上通过jwt的默认加密算法HMAC SHA256加密,也可以通过传入参数的方式改变加密算法。作者在使用其他加密算法时会报错Error: error:0909006C:PEM routines:get_name:no start line,可能因为这种算法需要设置public key的文件,具体操作方法不清楚。

完整版

const jwt = require('jsonwebtoken');

module.exports = class User extends require('./db') {
	static login (username, password) {
		return new Promise((resolve, reject) => {
			const sql = `select username, id from users where username=${username}&&password=${password}`;
			this.query(sql).then(res => {
				if (res[0].username === username) {
					const token = this.genetateToken(res[0]);
					resolve({
						code: 200,
						msg: '登录成功’,
						token
					})
				}
			}).catch(err => {
				console.log(err);
			})
		})
	}
	// generate token
	static generateToken(data) {
		const privateKey = 'myblog';
		const token = jwt.sign(data, privateKey, { expiresIn: 60 * 60 });
		return token;
	}
}
在路由处理程序中使用

./routes/users.js

const express = require('express');
const router = express.Router();
const User = require('../module/user')

/* GET users listing. */
router.post('/login', function(req, res, next) {
  console.log(req.body)
  const username = req.body.username;
  const password = req.body.password;
  User.login(username, password).then(result => {
    console.log(result)
    res.end(JSON.stringify(result))
  }).catch(err => {
    console.log(err)
  })
});

module.exports = router;

app.js中引入users.js时定义的路由是/users

var usersRouter = require('./routes/users');
app.use('/users', usersRouter);

所以完整的登录接口是/users/login

四、跨域

使用express-generator搭建的项目本身是有设置跨域响应头的,但不知道为什么我在前端项目中发送请求时依然存在跨域问题。为了解决这个问题,我使用了第三方插件cors

首先,安装

npm i cors

引入

const cors = require('cors')

使用

// basic 
app.use(cors());

// allow specific origin
app.use(cors({
	origin: 'http://localhost:8080',
	optionsSuccessStatus: 200
}))

五、上传文件功能

上传文件功能通过插件formidable实现。
/routes/upload.js

const express = require('express');
const router = express.Router();
const path = require('path');
// 引入formidable
const formidable = require('formidable');


/* upload one pic */
router.post('/', function(req, res, next) {
	// 创建实例
    const form = new formidable.IncomingForm();
    // 解码规则
    form.encoding='utf-8';
    // 保留文件扩展名
    form.keepExtensions=true;
    // 上传路径
    form.uploadDir =path.join(__dirname,"../public/images");
    // 保存
    form.parse(req,function(err,fields,files){
    	if (!err) {
    		res.end(JSON.stringify({fields,files}))
    	}
    })
});

/app.js

const upload= require('./routes/upload');
app.use('/upload', upload);

前端通过<input type="file" />上传文件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值