前言
这是一个基于node实现的一个简单登入例子,对于刚上手node想进一步了解,前端页面如何请求到服务层 -> 路由处理 -> 数据库操作 -> 返回结果到页面这整个过程的同学比较有用。这个例子基于github上两个项目(文末有链接),自己整理改写,希望有需要的同学可以看到。
项目源码地址:https://github.com/linwalker/node-login/tree/v1.0
技术栈
- node 使用 Koa框架,node版本7.6以上可以直接使用async/await;
- 使用mongoose来与Mongodb数据库连接交互;
- 前端使用react与antd-design组件;
- webpack 打包构建
环境准备与运行
- node.js >= 7.6
- mongodb 安装
- robomongo 安装 (mongodb的可视化工具)
- mongodb 新建名为node-login的数据库,并开启;
- npm install 安装依赖
- npm run build 代码构建
- node app 开启服务,可以访问localhost:3003/home
项目目录
node-login
|-- components //页面组件
|-- LoginTab.js
|-- RegisterTab.js
|-- controller //路由回调处理
|-- user-info.js
|-- models //用户模型
|-- user.js
|-- pages //页面js
|-- home
|-- home.js
|-- index.js
|-- main
|-- routes //路由
|-- static //静态文件
|-- tools //webpack构建文件
|-- views //页面模版
|-- .babelrc
|-- app.js //入口文件
|-- config.js //配置文件
|-- package.json
具体介绍
入口文件 - app.js
const Koa = require('koa');
const...
const app = new Koa();
// 配置控制台日志中间件
app.use(convert(koaLogger()));
// 使用ctx.body解析中间件
app.use(bodyParser());
// 配置服务端模板渲染引擎中间件
app.use(views(path.join(__dirname, './view'), {
extension: 'ejs'
}));
// 配置静态资源加载中间件
app.use(convert(koaStatic(
path.join(__dirname , './static')
)))
mongoose.Promise = global.Promise;
mongoose.connect(config.database);
// 初始化路由中间件
app.use(routers.routes()).use(routers.allowedMethods())
app.listen(3003);
console.log('The server is on prot 3003')
服务主要进行数据库连接,路由处理,静态文件配置和页面模板渲染。
配置文件 - config.js
module.exports = {
'secrect': 'linwalkernodelogindemo', //暂未用到,用于后期token验证
'database': 'mongodb://localhost:27017/node-login'//填写本地 mongodb 连接地址
};
主要设置连接mongodb数据的连接地址
用户模型 - user.js
定义登入注册的用户模型
const mongoose = require('mongoose');
const Schema = mongoose.Schema
const UserSchema = new Schema({
username: {
type: String,
unique: true,
require: true
},
password: {
type: String,
require: true
},
email: {
type: String,
}
});
module.exports = mongoose.model('User', UserSchema);
用户模型主要三个数据,用户名,密码和邮箱。
路由
路由总入口/routes/index.js
引入所有路由,使用koa-router中间件
const router = require('koa-router')();
const home = require('./home');
const main = require('./main');
const editor = require('./editor');
router.use('/home', home.routes(), home.allowedMethods());
router.use('/main', main.routes(), main.allowedMethods());
router.use('/editor', editor.routes(), editor.allowedMethods());
module.exports = router;
三个主路由为/home
,/main/
和/editor
,主要来看下/home
:
const router = require('koa-router')();
const userInfoController = require('./../controller/user-info');
const routers = router
.get('/', async (ctx) => {
const title = 'login home';
await ctx.render('home', {
title
})
})
.post('/signup', userInfoController.signUp)
.post('/signin', userInfoController.signIn)
module.exports = routers;
home.js
的get
请求返回home
页面,两个post请求,分别是注册和登入处理。我们来看下登入请求处理user-info.js
。
const User = require('./../models/user');
module.exports = {
async signUp (ctx) {
...
},
async signIn (ctx) {
let result = {
success: false,
message: '用户不存在'
};
//从请求体中获得参数
const { username, password } = ctx.request.body;
//检查数据库中是否存在该用户名
await User.findOne({
username
}, (err, user) => {
if (err) {
throw err;
}
if (!user) {
ctx.body = result;
} else {
//判断密码是否正确
if (password === user.password) {
ctx.body = {success: true, message: '登入成功'}
} else {
ctx.body = {success: false, message: '密码错误'}
}
}
})
}
}
登入请求处理过程为先检查用户名是否存在,在判断密码是否正确。在来看下页面发起请求的地方
登入请求
class LoginTab extends React.Component {
handleSubmit = async(e) => {
e.preventDefault();
let values = await this.getFormValues();
if (values) {
fetch('/home/signin', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(values)
}).then(res => {
res.json().then(res => {
Message.info(res.message);
if (res.success) {
location.href = '/main';
}
})
})
}
}
getFormValues() {
let self = this;
return new Promise((resolve, reject) => {
self.props.form.validateFields((err, values) => {
if (!err) {
resolve( values );
} else {
reject( false );
}
})
})
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<div style={{ width: "280px", margin: "0 auto" }}>
<Form onSubmit={this.handleSubmit}>
...
</Form>
</div>
)
}
}
export default Form.create()(LoginTab);
表单提交按钮绑定handleSubmit事件,该事件先获取表单提交数据,再发起/home/signin
的post请求,根据请求结果的success值,来决定是否跳转到成功页面。这里用到antd-design表单组件的相应属性。
操作演示
演示用户名不存在,密码错误及成功登入。
总结
- 使用了koa框架,主要是路由和ctx上下文的处理,没用过的同学可以点击koa2教程去看看,这是koa的一个入门教程写的很不错;
- 使用了mongoose操作数据库,栗子中涉及的不难,只是一个User模型,一个save保存数据和一个findOne查找,看下文档就明白,或则看下这篇文章
- 使用antd-design 组件