'假設你已經瞭解什麼是express框架 mongodb資料庫(非關係型資料庫) 那麼讓我們開始吧!'
Node.js的核心,通過npm下載或者自己有的包,require引入時不需要加/,
但是自己寫的模組則需要加,否則找不到,Node.js使用的是commonJs的模組
化規範哦
'讓我們開始吧!'
複製程式碼
github原始碼地址
專案需求
- 登陸,註冊,主頁,各一個介面(路由)
- 不需要靜態資源,需要前後端能互動,在對應的位置提醒使用者更新不同的內容
- 使用者如果不登陸,是不能訪問主頁。如果使用者在規定有效期內登陸成功過,也可以訪問主頁
- 使用者如果登陸/註冊失敗,要提醒對應的全部失敗原因,並且除了密碼外都要儲存在頁面中(不讓客戶重複輸入)
- 使用者的密碼在儲存資料庫中時,需要使用sha1的包進行加密,在查詢時候也需要加密
- 使用者的session_id也需要加密然後儲存在資料庫中
- 對使用者的session_id所對應的cookie也要設定一個有效期
- ...後續可能加一些防攻擊的需求,在應用型的中介軟體中。
所需要的下載的包
"dependencies": {
"cookie-parser": "^1.4.4", //解析cookie
"ejs": "^2.6.1", //ejs的模板渲染
"express": "^4.16.4", //express框架
"express-session": "^1.15.6", //session的處理
"mongoose": "^5.4.19" //mongoose包,處理mongodb資料庫的
},
"devDependencies": {
"nodemon": "^1.18.10", //每次修改JS檔案後伺服器自動更新
"sha1": "^1.1.1" //對資料加密的模組
}
'直接複製我上面的json檔案內容,把後面的註釋刪除掉即可 npm install 下載'
我們使用ejs的渲染引擎進行渲染
首先看主檔案的入口
-------
ejs.js
'這裡首先引入了express框架後,還引入了session的處理模組,以及自定義的uirouter、
inforrouter兩個路由器路由模組 ,設定了ejs的渲染目錄views,還指定了渲染
引擎為ejs(ejs的模組不需要引入,設定就好),'
const express = require('express');
const app = express();
const mongoose = require('./database');
const uirouter = require('./uirouter');
const inforouter = require('./inforouter');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
app.set('views', 'views');
app.set('view engine', 'ejs');
app.use(session({ //設定session
secret: 'hello', //對session_id的加密
saveUninitialized: false,
resave: false,
store: new MongoStore({
url: 'mongodb://localhost:27017/user',
touchAfter: 24 * 3600
}),
cookie:{maxAge:1000*3600*24*7},
//session是基於cookie傳送,cookie預設是會話儲存,需要指定有效期
}))
mongoose.then(async () => { //設定路由器路由,從下往下解析
app.use(uirouter);
app.use(inforouter);
})
app.use((err, req, res, next) => { //錯誤機制處理路由
if (err) {
console.log(err);
}
})
app.listen(5555, err => { //監聽埠號
if (!err) {
console.log('監聽成功');
} else {
console.log(`監聽失敗${err}`);
}
});
----------------
'database.js 這個是資料庫的連線模組 '
---------------------
'這裡暴露的是一個promise物件,必須先連線成功資料庫再走下一步,所以主模組使用了.then()'
const mongoose = require('mongoose');
module.exports = new Promise((resolve, reject) => {
mongoose.connect('mongodb://localhost:27017/user', { useNewUrlParser: true, useCreateIndex: true });
//指定連線的域名和埠號,以及資料庫的名稱
mongoose.connection.once('open', err => {
if (!err) {
console.log('資料庫連線成功');
resolve();
} else {
console.log('資料庫連線失敗:' + err);
reject(err);
}
})
})
---------------------
'model.js 這個是模型物件模組, 暴露的是模型物件,可以使用它身上對資料庫的CRUD操作'
const { Schema, model } = require('mongoose');
const schema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String,
required: true
}
});
const Model = model('userinfos', schema);
//指定資料庫的模型物件,以及儲存的集合名稱為 'userinfos'
module.exports = Model;
-----
'inforrouter 這個是註冊模組的檔案 '
const { Router, urlencoded } = require('express');
const sha1 = require('sha1');
const router = new Router();
const model = require('./model');
router.use(urlencoded({ extended: true }));
router.post('/login', async (req, res) => {
let { username, password } = req.body;
const result = await model.findOne({ username, password: sha1(password) });
//'如果能通過使用者名稱和加密後的密碼在資料庫中查詢到,那麼給它新增session_id然後跳轉到主頁'
if (result) {
req.session.userid = result.id
res.redirect('/index')
} else {
res.render('login', { err: { username: username, usernameerr: '使用者名稱或密碼錯' } });
//'如果找不到,渲染login.ejs檔案,並且渲染對應的err資料到頁面上'
}
})
router.post('/re', async (req, res) => {
let { username, password, repassword, email } = req.body;
//ES6的解構賦值,提取post請求體中的四個對應的數值
const usernameReg = /^[A-Za-z0-9_]{5,10}$/;
const passwordReg = /^[A-Za-z0-9_]{5,12}$/;
const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
//三個正則匹配
let err = {};
const result = await model.findOne({ username });
if (!usernameReg.test(username)) {
err.usernameerr = '使用者名稱格式不正確';
}
if (!passwordReg.test(password)) {
err.password = '密碼格式不正確';
}
if (password != repassword) {
err.repassword = '跟上次輸入密碼不一致';
}
if (!emailReg.test(email)) {
err.email = '郵箱格式不正確';
}
if (result) {
err.usernameerr = '使用者名稱已存在'
}
if (err.usernameerr || err.password || err.repassword || err.emailerr) {
res.render('re', { err })
return;
//'只要有一個錯誤存在,那麼就渲染re.ejs檔案,並且渲染err這個資料'
}
model.create({
username,
password: sha1(password),
email
})
res.redirect('/index')
//'如果上面的錯誤都沒有,那麼就儲存這個文件物件在資料庫中,
並且跳轉到index的路由上,index的路由也有處理機制'
})
module.exports = router;
------------
'uirouter.js 是處理get請求的路由檔案'
----------------
const { Router } = require('express');
const model = require('./model');
const router = new Router();
router.get('/login', async (req, res) => {
res.render('login.ejs', { err: '' })
//'渲染對應的ejs檔案,這裡如果不寫空的err渲染資料,
後期的渲染會報錯,會提示err not defined'
})
router.get('/re', (req, res) => {
res.render('re.ejs', { err: "" });
})
router.get('/index', async (req, res) => {
const { userid } = req.session;
if (!userid) {
res.redirect('/login')
return;
}
const result = await model.findById({ _id: userid });
if (result) {
res.render('index');
} else {
res.redirect('/login');
}
//'如果使用者成功登陸過,那麼會有一個session_id檔案,
如果有並且能在資料庫中找到,那麼就讓使用者去index.ejs
的渲染檔案'
})
module.exports = router;
-----------------
'views資料夾,下面的三個ejs檔案,是使用ejs渲染引擎的渲染檔案'
'index.ejs '
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>歡迎來到首頁</h1>
<a href="/login">登陸介面</a>
<a href="/re">註冊介面</a>
</body>
</html>
-------------------------
'login.ejs 是登陸檔案'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.err{
color:red;
}
</style>
</head>
<body>
<form action="/login" method="post">
<label for="username">使用者名稱</label>
<input type="text" name="username" value=<%= err.username %> ><span class="err"> <%= err.usernameerr %> </span> <br />
<label for="password">密碼</label>
<input type="password" name="password"><span class="err"> </span> <br />
<input type="submit" value='登陸'>
</form>
</body>
</html>
-------------------
're.js 是註冊頁面檔案 '
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.err{
color:red;
}
</style>
</head>
<body>
<form action="/re" method="post">
<label for="username">使用者名稱</label>
<input type="text" name="username" value=<%= err.username %> ><span class='err'><%= err.usernameerr %></span><br />
<label for="password">密碼</label>
<input type="password" name="password"><span class='err'><%= err.password%></span><br />
<label for="repassword">再次確認密碼</label>
<input type="password" name="repassword"><span class='err'><%= err.repassword%></span><br />
<label for="email">郵箱</label>
<input type="text" name="email" value=<%= err.email %> ><span class='err'><%= err.emailerr%></span><br />
<input type="submit" value='註冊'>
</form>
</body>
</html>
--------------------------
'在瀏覽器中輸入的url地址訪問都是get請求,所以我們把get請求也成為uirouter,但是一旦到了提交表單,
我們使用的就是post請求的路由了,同樣名字的路由,但是請求方式不一樣他們並不衝突,Node.js中程式碼
也是從上到下解析的,這裡的ejs渲染模板需要多注意的是get請求的時候一定要先給一個空的渲染資料,否
則後期post請求是渲染不上去的,會提示not defined,因為肯定是先get請求看到頁面後才能提交資料,這
點要格外注意,其實express框架並不難,這個版本就能用到express中最核心的所有知識點,能掌握了就能
獨立開發伺服器和前後端互動以及資料處理',後面我會就web的儲存技術,以及koa2框架繼續深入
複製程式碼