一、Node.js預設使用commonJs的模組化方案,TypeScript預設是ES6的模組化方案,兩者有本質區別。
-
1.
Node.js
的去尋找引入的依賴時,如果是Node自帶的模組,比如fs檔案模組,只需要填寫fs即可。如果是自己定義的模組,那麼需要加入./(使用相對路徑),暴露介面使用exports
或者module.exports
-
2.TypeScript的
import * from url
的引入依賴,需要填寫完整的相對路徑,否則是找不到模組的,暴露介面使用export
. -
3.Node中使用
TypeScript
需要下一些包去支援,比如express
框架這些,還有一些支援內建物件的包:
"dependencies": {
"@babel/core": "^7.4.0",
"@types/core-js": "^2.5.0",
"browserify": "^16.2.3",
"connect-mongo": "^2.0.3",
"cookie-parser": "^1.4.4",
"ejs": "^2.6.1",
"express": "^4.16.4",
"express-session": "^1.15.6",
"mongoose": "^5.4.19",
"nodemon": "^1.18.10",
"sha1": "^1.1.1"
},
"devDependencies": {
"@types/express": "^4.16.1",
"@types/node": "^11.11.4",
"ts-loader": "^5.3.3",
"ts-node-dev": "^1.0.0-pre.32",
"typescript": "^3.3.4000",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0"
}
'具體還需要什麼,可以上網去搜尋下'
複製程式碼
二、入口檔案,我們使用 ejs
引擎渲染(res.render()
)
-
1.Node.js使用
ejs
渲染的核心技巧是渲染資料的指定 -
2.儘量一個渲染資料物件包括所有的渲染內容
-
3.一個渲染物件可以有很多個屬性,每次get請求
時先傳送一個空的物件到後端,再根據需求邏輯指定
物件屬性和內容,最後還是傳輸那個物件回來。避免了
傳送過多的物件,程式碼看起來很複雜
- 4.渲染資料的位置在渲染的ejs檔案中的放置,
如果需要樣式,可以事先在HTML結構中包一層
HTML
結構, 然後用CSS定義好。
'這是Node.js版本'
'//入口檔案使用了兩個路由器路由,分別處理get和post請求邏輯。
即使是同一個路由,但是請求方式不一樣,他們的處理邏輯不會衝突'
const express = require('express');
const db = require('./common/db');
const app = express();
const uirouter = require('./router/uirouter');
const postrouter = require('./router/postrouter');
app.set('views', 'views');
app.set('view engine', 'ejs');
db.then(() => {
app.use(uirouter);
app.use(postrouter);
})
app.listen(8080, err => {
if (!err) {
console.log('埠號監聽成功')
} else {
console.log('埠監聽失敗', err)
}
})
-----------------
'這是TypeScript版本'
import express from './node_modules/@types/express/index';
import db from './common/db1';
import uirouter from './router/uirouter1';
import postrouter from './router/postrouter1';
const app: any = express();
app.set('views', 'views');
app.set('view engine', 'ejs');
db.then((): void => {
app.use(uirouter);
app.use(postrouter);
});
app.listen(8080, (err): void => {
if (!err) {
console.log('伺服器連線成功');
} else {
console.log('伺服器連線成功');
};
});
複製程式碼
三、get請求的路由處理模組
-
1.路由模組的核心,一個路由處理一個邏輯
-
2.
res.end / send / render
後面再寫邏輯也不會執行了,因為已經返回響應。 -
3.對於
cookie
的使用我們需要依賴第三方中介軟體 -
4.
res.render()
裡面是寫ejs渲染的檔案,所以可以不用寫ejs的字尾 -
5.
res.redirect()
裡面寫的是定向的那個路由,指定前往那個路由,
然後根據那個路由的邏輯處理,此時瀏覽器中的url
會改變。這就叫重定向
'//這裡我們使用了第三方中介軟體處理cookie並且
攜帶資料,大概設計思路:
1.沒有登入過不能進入個人中心,會跳轉到登入介面
2.登入過後會有一個免登入期限進入個人中心
3.在登入介面可以通過使用者名稱和郵箱找回密碼
4.在 Node 端處理邏輯,只有res.redirect()可以
改變瀏覽器的網址,切記。
5.每個路由器路由代表每個不同的邏輯
6.get模組只處理渲染哪個頁面的邏輯'
const { Router } = require('express');
const model = require('../common/model');
const cookieParse = require('cookie-parser');
const router = new Router();
router.use(cookieParse())
router.get('/index', (req, res) => {
res.render('index.ejs', { err: "" })
})
router.get('/', (req, res) => {
res.redirect('/index');
});
router.get('/login', (req, res) => {
res.render('login.ejs', { err: "" });
});
router.get('/register', (req, res) => {
res.render('register.ejs', { err: "" });
});
router.get('/reset', (req, res) => {
res.render('reset.ejs', { err: '' });
});
router.get('/usercenter', async (req, res) => {
const result = await model.findOne({ _id: req.cookies.userid });
if (!result) {
res.redirect('/login')
return
}
res.render('usercenter.ejs', { err: "" });
});
module.exports = router;
複製程式碼
四、post
模組,處理各種資料庫的CRUD操作,後臺邏輯。(核心)
- 1.
CRUD
操作全部依賴模型物件來執行。 - 2.限制物件一旦生成那麼無法改變,除非刪除資料庫
- 3.限制物件的增刪改查都返回的是一個promise物件,
如果這時候去 if()
裡判斷,無論有什麼樣的結果,都是true
,
而且這個CRUD
操作都是非同步,所以我們把外部函式變成 async
函式,
這樣可以配合await
實現最佳非同步,還可以獲取他們的返回值進行
if
判斷。(Node.js的後端核心)
const { Router } = require('express');
const express = require('express');
const model = require('../common/model');
const cookieParse = require('cookie-parser');
const sha1 = require('sha1');
const router = new Router();
router.use(cookieParse())
router.use(express.urlencoded({ extended: true }))
router.post('/login', async (req, res) => {
const { username, password } = req.body;
const result = await model.findOne({ username, password: sha1(password) });
if (!result) {
res.render('login', { err: { usernameloginerr: '使用者名稱或密碼錯', username: username } })
return;
}
const userid = result.id;
res.cookie('userid', userid, {maxAge:1000*60*10});
res.redirect('/usercenter')
return
});
router.post('/register', async (req, res) => {
const { username, password, repassword, email } = req.body;
const err = {};
const usernameReg = /^[A-Za-z0-9_]{5,10}$/;
const passwordReg = /^[A-Za-z0-9_]{5,12}$/;
const emailReg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
if (!usernameReg.test(username)) {
err.usernamereerr = '使用者名稱格式錯誤';
}
if (!passwordReg.test(password)) {
err.passworderr = '密碼格式錯誤';
}
if (repassword !== password) {
err.repassworderr = '兩次密碼輸入不一致';
}
if (!emailReg.test(email)) {
err.emailerr = '郵箱格式錯誤';
}
const usernameresult = await model.findOne({ username });
if (usernameresult) {
err.usernamereerr = '使用者名稱已存在';
res.render('register', { err })
return
};
const emailresult = await model.findOne({ email });
if (emailresult) {
err.emailerr = '郵箱已被註冊';
res.render('register', { err })
return
}
if (err.usernamereerr || err.passworderr || err.repassworderr || err.emailerr) {
err.username = username;
err.email = email;
res.render('register', { err })
return
}
model.create({
username: username,
password: sha1(password),
email: email
})
res.redirect('/index')
});
router.post('/reset', async (req, res) => {
const { username, password, repassword, email } = req.body;
const err = {};
const result = await model.findOne({ username, email });
if (!result) {
if (repassword !== password) {
err.repassworderr = '兩次密碼輸入不一致'
}
err.usernamereerr = '使用者名稱或者郵箱輸入有誤';
err.emailerr = '使用者名稱或者郵箱輸入有誤';
res.render('reset.ejs', { err })
return
} else {
await model.updateOne({ username, email }, { password: sha1(password) });
res.redirect('/usercenter');
return
}
})
module.exports = router;
複製程式碼
五、工具類模組 model物件和database模組 有天坑
需要注意
限制物件一旦生成那麼無法改變,除非刪除資料庫
'database模組'
const mongoose = require('mongoose');
module.exports = new Promise((resolve, reject) => {
mongoose.connect('mongodb://localhost:27017/userinfos', { useCreateIndex: true, useNewUrlParser: true });
mongoose.connection.once('open', err => {
if (!err) {
console.log('資料庫連線成功')
resolve()
} else {
console.log('資料庫連線失敗', err)
reject(err)
}
})
})
------
'model物件模組'
'這裡定義限制物件時,一定要考慮好,
否則資料庫連線啟動後,除非刪除資料庫,
不然無法修改限制物件的內容!!!!'
const { Schema, model } = require('mongoose');
const ajaxschema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String,
unique: true,
required: true
},
})
const model1 = model('userinfo', ajaxschema);
module.exports = model1;
複製程式碼
六、 ejs
的渲染目錄
ejs
的渲染資料在ejs檔案中的格式有三種- 1.
<% data %>
裡面可以寫任意程式碼 - 2.
<%= data %>
裡面寫的程式碼最終會轉義後再出現(推薦) - 3.
<%- data %>
裡面寫的程式碼最終不會轉義後就出現(不安全)
'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="http://localhost:8080/login">登陸</a>
<a href="http://localhost:8080/register">註冊</a>
<a href="http://localhost:8080/usercenter">個人中心</a>
</body>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script>
</script>
</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>
</head>
<body>
<form method="post" action="/login">
<label for="username">使用者名稱</label>
<input type="text" name="username" value=<%= err.username %>><%= err.usernameloginerr %> <br />
<label for="password">密碼</label>
<input type="password" value="" name="password">
<input type="submit" id="sub">
</form>
<a href='/reset'>找回密碼</a>
</body>
<script>
</script>
</html>
------------
'register.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>
<form method="post" action="/register">
<label for="usern ame">使用者名稱</label>
<input type="text"name="username" value= <%= err.username %> > <%= err.usernamereerr %></br>
<label for="password">密碼</label>
<input type="password" value="" name="password"> <%= err.passworderr %></br>
<label for="repassword">再次確認密碼</label>
<input type="password" value="" name="repassword"> <%= err.repassworderr %></br>
<label for="email">郵箱</label>
<input type="text" name="email" value= <%= err.email %> > <%= err.emailerr %></br>
<input type="submit">
</form>
</body>
</html>
-----------
'reset.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>
<form method="post" action="/reset">
<label for="usern ame">您註冊的使用者名稱</label>
<input type="text" name="username" value=<%= err.username %>> <%= err.usernamereerr %></br>
<label for="password">重置後的密碼</label>
<input type="password" value="" name="password"> <%= err.passworderr %></br>
<label for="repassword">請再次確認密碼</label>
<input type="password" value="" name="repassword"> <%= err.repassworderr %></br>
<label for="email">您的註冊郵箱</label>
<input type="text" name="email" value=<%= err.email %>> <%= err.emailerr %></br>
<input type="submit">
</form>
</body>
</html>
------
'usercenter.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="/index">返回主頁</a>
</body>
</html>
------
複製程式碼