DNS解析,創建TCP鏈接,發送http請求php
server接收到http請求,處理而且返回數據html
客戶端接收到返回數據,處理數據(渲染頁面,執行JavaScript腳本)前端
get請求和querystringnode
post請求和postdatamysql
路由linux
const http = require('http')
const querystring = require('querystring')
const server = http.createServer((req, res) => {
const url = req.url;
const method = req.method;
req.query = querystring.parse(url.split('?')[1])
console.log("url:" + url);
console.log("method:" + method)
console.log(req.query)
res.end(JSON.stringify(req.query))
})
server.listen(3000);
console.log('listen on port 3000')
複製代碼
post請求,即客戶端要向服務器傳遞數據,如新建文章nginx
經過post data傳遞數據git
瀏覽器沒法直接模擬,須要手寫js,或者使用postmangithub
安裝postman,app或者離線安裝插件版web
const http = require('http')
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let postData = '';
console.log('content-type:' + req.headers['content-type'])
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
console.log(postData)
res.end(postData)
})
}
})
server.listen(3000)
console.log('listen on port 3000')
複製代碼
const http = require('http');
const server = http.createServer((req, res) => {
const url = req.url
const path = url.split('?')[0]
// 返回路由
res.end(path);
})
server.listen(3000)
console.log('listen on port 3000')
複製代碼
const http = require('http')
const querystring = require('querystring')
const server = http.createServer((req, res) => {
const method = req.method
const url = req.url
const path = url.split('?')[0]
const query = querystring.parse(url.split('?')[1])
// 設置返回格式
res.setHeader('Content-type', 'application/json')
const resData = {
method,
url,
path,
query
}
if (resData.method === 'GET') {
res.end(
JSON.stringify(resData)
)
}
if (resData.method === 'POST') {
let postData = ''
req.on('data', chunk => postData += chunk.toString())
req.on('end', () => {
resData.postData = postData
res.end(
JSON.stringify(resData)
)
})
}
})
server.listen(3000)
console.log('ok')
複製代碼
從0開始搭建,不使用框架
使用nodemon 監測文件變化,自動重啓node
使用cross-env 設置環境變量,兼容mac linux windows
初始化路由:根據以前技術方案的設計,作出路由
返回假數據,將路由和數據處理分離,以符合設計原則
接口:/api/blog/list
方法:get
url參數:author,keyword
接口:/api/blog/detail
方法:get
url參數:id
接口:/api/blog/new
方法:post
描述:post新增的文章數據
接口:/api/blog/update
方法:post
參數:id
描述:post更新的內容
接口:/api/blog/del
方法:post
參數:id
接口:/api/user/login
方法:post
參數:id
描述:post用戶名和密碼
// 建立目錄
mkdir blog-01 && cd blog-01
// 初始化package.json
npm init -y
// 安裝工具lodash,主要是後續操做數據
npm install lodash --save-dev
// 全局安裝nodemon,方便咱們修改文件的時候自動重啓node
npm install nodemon -g
// 建立bin目錄而且在該目錄下建立主文件
mkdir bin && cd bin
type nul>www.js
複製代碼
主文件:www.js
const http = require('http')
const serverHandle = require('../app.js')
const POST = 3000
const server = http.createServer(serverHandle)
server.listen(POST)
console.log('listen on port ' + POST)
複製代碼
cd到根目錄下,建立app.js
type nul>app.js
複製代碼
const querystring = require('querystring')
const serverHandle = (req, res) => {
res.setHeader('Content-type', 'application/json')
res.end('hello')
}
module.exports = serverHandle
複製代碼
cd到根目錄下,建立對應的文件和文件夾
// 建立src目錄,後續原生的代碼幾乎都放在這裏
mkdir src && cd src
// 建立路由目錄
mkdir router && cd router
// 分別建立博客路由和用戶登陸路由文件
type nul>blog.js
type nul>user.js
複製代碼
blog.js
const handleBlogRouter = (req, res) => {
const method = req.method
const path = req.url.split('?')[0]
// 獲取博客列表
if (method === 'GET' && path === '/api/blog/list') {
return {
msg: '這是獲取博客列表的接口'
}
}
// 獲取博客內容
if (method === 'GET' && path === '/api/blog/detail') {
return {
msg: '這是獲取博客詳情的接口'
}
}
// 新增文章
if (method === 'POST' && path === '/api/blog/new') {
return {
msg: '這是新增文章的接口'
}
}
// 文章更新
if (method === 'POST' && path === '/api/blog/update') {
return {
msg: '這是文章更新的接口'
}
}
// 文章刪除
if (method === 'POST' && path === '/api/blog/del') {
return {
msg: '這是文章刪除的接口'
}
}
}
module.exports = {
handleBlogRouter
}
複製代碼
user.js
const handleUserRouter = (req, res) => {
const method = req.method
const path = req.url.split('?')[0]
// 登陸
if (method === 'POST' && path === '/api/user/login') {
return {
msg: '這是登陸的接口'
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
app.js
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const serverHandle = (req, res) => {
res.setHeader('Content-type', 'application/json')
const blogData = handleBlogRouter(req, res)
if (blogData) {
res.end(
JSON.stringify(blogData)
)
return
}
const userData = handleUserRouter(req, res)
if (userData) {
res.end(
JSON.stringify(userData)
)
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
}
module.exports = serverHandle
複製代碼
cd到根目錄
nodemon bin/www.js
複製代碼
cd到src目錄下
// 建立模型目錄
mkdir model && cd model
// 建立返回結果模型文件
type nul>resModel.js
複製代碼
resModel.js
class BaseModel {
constructor(data, message) {
// 若是傳過來的data是字符串,那就把他設置爲message的值,而且將傳過來的變量設置爲null,使得下面的賦值不執行
if (typeof data === 'string') {
this.message = data
data = null
message = null
}
if (data) {
this.data = data
}
if (message) {
this.message = message
}
}
}
class SuccessModel extends BaseModel {
constructor(data, message) {
super(data, message)
this.errno = 0
}
}
class ErrorModel extends BaseModel {
constructor(data, message) {
super(data, message)
this.error = -1
}
}
module.exports = {
SuccessModel,
ErrorModel
}
複製代碼
cd到src目錄下
// 建立控制器文件夾,該文件夾下的文件用於根據一些參數返回數據
mkdir controller && cd controller
// 建立命中blog路由時獲取數據的函數
type nul>BlogController.js
複製代碼
BlogController.js
// 獲取文章列表
const getList = (author, keyword) => {
// 先返回一些死數據,可是格式是對
return [
{
id: 1,
title: '標題1',
content: '內容A',
createTime: 1564136537100,
author: 'zhangsan'
},
{
id: 2,
title: '標題2',
content: '內容B',
createTime: 1564136647326,
author: 'lisi'
}
]
}
// 獲取文章詳情
const getDetail = (id) => {
if (id) {
return {
id: 1,
title: '標題1',
content: '內容A',
createTime: 1564136647326,
author: 'lisi'
}
} else {
return null
}
}
module.exports = {
getList,
getDetail
}
複製代碼
app.js
const querystring = require('querystring')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const serverHandle = (req, res) => {
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
res.setHeader('Content-type', 'application/json')
const blogData = handleBlogRouter(req, res)
if (blogData) {
res.end(
JSON.stringify(blogData)
)
return
}
const userData = handleUserRouter(req, res)
if (userData) {
res.end(
JSON.stringify(userData)
)
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
}
module.exports = serverHandle
複製代碼
blog.js【router】
const { getList, getDetail } = require('../controller/BlogController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleBlogRouter = (req, res) => {
// 獲取博客列表
if (req.method === 'GET' && req.path === '/api/blog/list') {
const author = req.query.author || ''
const keyword = req.query.keyword || ''
const listData = getList(author, keyword)
return new SuccessModel(listData, '數據獲取成功')
}
// 獲取博客內容
if (req.method === 'GET' && req.path === '/api/blog/detail') {
const id = req.query.id || null
const detailData = getDetail(id)
if (detailData) {
return new SuccessModel(detailData, '數據獲取成功')
} else {
return new ErrorModel('數據獲取失敗')
}
}
// 新增文章
if (req.method === 'POST' && req.path === '/api/blog/new') {
return
}
// 文章更新
if (req.method === 'POST' && req.path === '/api/blog/update') {
return {
msg: '這是文章更新的接口'
}
}
// 文章刪除
if (req.method === 'POST' && req.path === '/api/blog/del') {
return {
msg: '這是文章刪除的接口'
}
}
}
module.exports = {
handleBlogRouter
}
複製代碼
cd到blog-01同級目錄,新建一個目錄名稱爲promise-test
// 建立而且進入該測試文件夾
mkdir promise-test && cd promise-test
// 建立入口文件
type nul>index.js
// 建立被讀取的文件夾目錄和文件
mkdir file && cd file
type nul>a.json
type nul>b.json
type nul>c.json
複製代碼
a.json
{
"path": "b.json",
"data": "aaa"
}
複製代碼
b.json
{
"path": "c.json",
"data": "bbb"
}
複製代碼
c.json
{
"path": "d.json",
"data": "ccc"
}
複製代碼
index.js
// fs是node裏面一個操做文件的對象
const fs = require('fs')
// path是node裏處理路徑的對象
const path = require('path')
// 拼接等待讀取的文件路徑
const fullFileName = path.resolve(__dirname, 'file', 'a.json')
// 調用readFile方法,異步打印出讀取的文件流
fs.readFile(fullFileName, (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data.toString())
})
複製代碼
cd到promise-test目錄
node index.js // 讀取a.json的內容
複製代碼
修改promise-test下的index.js文件
const fs = require('fs')
const path = require('path')
function getFileContent(fileName, callback) {
const fullFileName = path.resolve(__dirname, 'file', fileName)
fs.readFile(fullFileName, (err, data) => {
if (err) {
console.error(err)
return
}
callback(
JSON.parse(data.toString())
)
})
}
// 回調地獄
getFileContent('a.json', (aData) => {
console.log(aData)
getFileContent(aData.path, (bData) => {
console.log(bData)
getFileContent(bData.path, (cData) => {
console.log(cData)
})
})
})
複製代碼
node index.js // 經過回調函數,讀取各個文件的內容
複製代碼
修改promise-test下的index.js文件
const fs = require('fs')
const path = require('path')
function getFileContent(fileName) {
return new Promise((resolve, reject) => {
const fullFileName = path.resolve(__dirname, 'file', fileName)
fs.readFile(fullFileName, (err, data) => {
if (err) {
reject(err)
return
}
resolve(
JSON.parse(data.toString())
)
})
})
}
getFileContent('a.json').then(aData => {
console.log(aData)
return getFileContent(aData.path)
}).then(bData => {
console.log(bData)
return getFileContent(bData.path)
}).then(cData => {
console.log(cData)
})
複製代碼
node index.js // 經過return promise,讀取各個文件的內容
複製代碼
ok,有了上面的promise基礎,如今從新回到blog-01處理post方法的接口
cd到blog-01目錄下,修改app.js
const querystring = require('querystring')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') {
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') {
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(
JSON.parse(postData)
)
} else {
resolve({})
return
}
})
})
return promise
}
const serverHandle = (req, res) => {
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
res.setHeader('Content-type', 'application/json')
getPostData(req).then(postData => {
req.body = postData
const blogData = handleBlogRouter(req, res)
if (blogData) {
res.end(
JSON.stringify(blogData)
)
return
}
const userData = handleUserRouter(req, res)
if (userData) {
res.end(
JSON.stringify(userData)
)
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
})
}
module.exports = serverHandle
複製代碼
修改router下的blog.js
const { getList, getDetail, newBlog, updateBlog, delBlog } = require('../controller/BlogController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleBlogRouter = (req, res) => {
// 獲取博客列表
if (req.method === 'GET' && req.path === '/api/blog/list') {
const author = req.query.author || ''
const keyword = req.query.keyword || ''
const listData = getList(author, keyword)
return new SuccessModel(listData, '數據獲取成功')
}
// 獲取博客內容
if (req.method === 'GET' && req.path === '/api/blog/detail') {
const id = req.query.id || null
const detailData = getDetail(id)
if (detailData) {
return new SuccessModel(detailData, '數據獲取成功')
} else {
return new ErrorModel('數據獲取失敗')
}
}
// 新增文章
if (req.method === 'POST' && req.path === '/api/blog/new') {
const newData = newBlog(req.body)
return new SuccessModel(newData)
}
// 文章更新
if (req.method === 'POST' && req.path === '/api/blog/update') {
const id = req.query.id
const updateResult = updateBlog(id, req.body)
if (updateResult) {
return new SuccessModel("更新文章成功")
} else {
return new ErrorModel("更新文章失敗")
}
}
// 文章刪除
if (req.method === 'POST' && req.path === '/api/blog/del') {
const id = req.query.id
const delResult = delBlog(id)
if (delResult) {
return new SuccessModel()
} else {
return new ErrorModel("刪除失敗")
}
}
}
module.exports = {
handleBlogRouter
}
複製代碼
修改controller下的BlogController.js
// 獲取文章列表
const getList = (author, keyword) => {
// 先返回一些死數據,可是格式是對
return [
{
id: 1,
title: '標題1',
content: '內容A',
createTime: 1564136537100,
author: 'zhangsan'
},
{
id: 2,
title: '標題2',
content: '內容B',
createTime: 1564136647326,
author: 'lisi'
}
]
}
// 獲取文章詳情
const getDetail = (id) => {
if (id) {
return {
id: 1,
title: '標題1',
content: '內容A',
createTime: 1564136647326,
author: 'lisi'
}
} else {
return null
}
}
// 新增一篇文章
const newBlog = (blogData = {}) => {
return {
id: 3,
blogData
}
}
// 更新一篇文章
const updateBlog = (id, blogData = {}) => {
return true
}
// 刪除一篇文章
const delBlog = (id) => {
return true
}
module.exports = {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
}
複製代碼
cd到src下的controller下
type nul>UserController.js
複製代碼
UserController.js
const login = (username, password) => {
if (username === 'zhangsan' && password === '123') {
return true
}
return false
}
module.exports = {
login
}
複製代碼
router下的user.js
const { login } = require('../controller/UserController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// 登陸
if (req.method === 'POST' && req.path === '/api/user/login') {
const { username, password } = req.body
const loginResult = login(username, password)
if (loginResult) {
return new SuccessModel("登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
路由和假數據這塊基本就已經完成了
總結:postman使用來進行接口測試,路由和數據分開,新建數據模型用於格式化數據,promise異步處理數據
web server中最流行的關係型數據庫
官網能夠免費下載
輕量級,易學易用
mysql下載地址:dev.mysql.com/downloads/m…
固然也能夠經過下載集成有數據庫環境的phpstudy來獲取數據庫環境
數據庫圖形工具workbench下載:dev.mysql.com/downloads/w…
在workbench中,schema就是庫的意思
// 建立數據庫myblog
CREATE SCHEMA `myblog`
// 刪除數據庫myblog
DROP SCHEMA `myblog`
// 使用數據庫myblog
use myblog
複製代碼
CREATE TABLE myblog.users (
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(20) NOT NULL,
`password` VARCHAR(20) NOT NULL,
`realname` VARCHAR(10) NOT NULL,
PRIMARY KEY (id));
複製代碼
CREATE TABLE `myblog`.`blogs` (
`id` INT NOT NULL AUTO_INCREMENT,
`title` VARCHAR(50) NOT NULL,
`content` LONGTEXT NOT NULL,
`createtime` BIGINT(20) NOT NULL DEFAULT 0,
`author` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`));
複製代碼
增刪改查
// 使用數據庫,操做以前務必選中要使用的庫
use myblog;
// 列出該數據庫中的全部表
show tables;
// 註釋
--show tables;
// 插入語句
insert into users(`username`, `password`, `realname`) values('zhangsan','123','張三');
insert into users(`username`, `password`, `realname`) values('lisi','123','李四');
insert into blogs(`title`, `content`, `createtime`, `author`) values('標題1','內容1','1564452004248', 'zhangsan');
insert into blogs(`title`, `content`, `createtime`, `author`) values('標題2','內容2','1564452013359', 'lisi');
// 查詢users表全部的行和列
select * from users
// 查詢某個列的數據
select username,password from users
// 查詢符合某個條件的行(查詢交集)
select * from users where `username`='zhangsan' and `password`='123';
// 查詢符合某個條件的行(查詢並集)
select * from users where `username`='zhangsan' or `password`='123';
// 模糊查詢
select * from users where username like '%zhang%';
// 排序(desc倒敘,asc升序)
select * from users where username like '%zhang%' order by id desc
// 更新
update users set `realname`="李四" where `username`='lisi';
// 接觸更新限制
SET SQL_SAFE_UPDATES=0
// 刪除數據
delete from users where username='lisi';
// 通常建議新建一個字段,state設置0或1 來作僞刪除。
ALTER TABLE `myblog`.`blogs`
ADD COLUMN `state` INT NOT NULL DEFAULT 1 AFTER `author`;
// 設置state的狀態來標記數據是否顯示
update blogs set `state` = 0 where `username` = 'lisi'
// 注意:varchar(10)只能存儲10個漢字,10個字母
複製代碼
新建demo進行演示,封裝爲系統可用的工具,讓api直接操做數據庫,再也不使用假數據
mkdir node-mysql-test && cd node-mysql-test
type nul>index.js
npm init -y
npm install mysql
dir
複製代碼
進入index.js文件
// 引入mysql
const mysql = require('mysql')
// 建立鏈接對象
const conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
})
// 鏈接對象進行鏈接
conn.connect()
// 定義sql語句
const sql = 'select * from blogs'
// 執行sql語句
conn.query(sql, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
// 關閉鏈接
conn.end()
複製代碼
cd到blog-01
cd blog-01
// 安裝mysql
npm install mysql --save-dev
// 安裝cross-env
npm install cross-env --save-dev
// 進入package.json,在 scripts下添加
"dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js",
"prd": "cross-env NODE_ENV=production nodemon ./bin/www.js"
// cd到src下
cd src
// 建立conf文件夾
mkdir conf && cd conf
// 建立db.js,用於數據庫配置
type nul>db.js
複製代碼
db.js
const env = process.env.NODE_ENV
let MYSQL_CONF
// 根據我的開發環境修改
if (env === 'dev') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
}
}
if (env === 'production') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog2'
}
}
module.exports = {
MYSQL_CONF
}
複製代碼
cd到src目錄
mkdir db && cd db
// 建立mysql鏈接文件,用於鏈接數據庫
type nul>mysql.js
複製代碼
mysql.js
const mysql = require('mysql')
const { MYSQL_CONF } = require('../conf/db')
const conn = mysql.createConnection(MYSQL_CONF)
conn.connect()
function exec(sql) {
return new Promise((resolve, reject) => {
conn.query(sql, (err, result) => {
if (err) {
reject(err)
return
} else {
resolve(result)
}
})
})
}
module.exports = {
exec
}
複製代碼
BlogController.js
const { exec } = require('../db/mysql')
// 獲取文章列表
const getList = (author, keyword) => {
let sql = `select * from blogs where 1 = 1`
sql += author ? ` and author = '${author}'` : ''
sql += keyword ? ` and title like '%${keyword}%'` : ''
sql += ` order by createtime desc;`
return exec(sql)
}
// 獲取文章內容
const getDetail = (id) => {
let sql = `select * from blogs where id = ${id}`
return exec(sql).then(rows => {
return rows[0]
})
}
// 新增一篇文章
const newBlog = (blogData = {}) => {
const { title=null, content=null, author=null } = blogData
const createTime = Date.now()
let sql = `insert into blogs(title, content, createtime, author) values('${title}','${content}',${createTime}, '${author}')`;
return exec(sql).then(result => {
return {
insertId: result.insertId
}
})
}
// 更新一篇文章
const updateBlog = (id, blogData = {}) => {
const { title, content } = blogData
let sql = `update blogs set id = ${id}`
sql += title ? `, title = '${title}'` : ''
sql += content ? `, content = '${content}'` : ''
sql += ` where id = ${id}`
if (id !== null) {
return exec(sql).then(result => {
return {
affectedRows: result.affectedRows
}
})
} else {
return new Promise((resolve, reject) => {
resolve(false)
})
}
}
// 刪除一篇文章
const delBlog = (id, author) => {
let sql = `delete from blogs where id = ${id} and author = '${author}'`
if (id) {
return exec(sql).then(result => {
return {
affectedRows: result.affectedRows
}
})
} else {
return new Promise((resolve, reject) => {
resolve(false)
})
}
}
module.exports = {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
}
複製代碼
router下blog.js
const { getList, getDetail, newBlog, updateBlog, delBlog } = require('../controller/BlogController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleBlogRouter = (req, res) => {
// 獲取博客列表
if (req.method === 'GET' && req.path === '/api/blog/list') {
const author = req.query.author || ''
const keyword = req.query.keyword || ''
return getList(author, keyword).then(listData => {
return new SuccessModel(listData, '數據獲取成功')
})
}
// 獲取博客內容
if (req.method === 'GET' && req.path === '/api/blog/detail') {
const id = req.query.id || null
if (id === null) {
return new Promise((resolve) => {
resolve(false)
}).then(() => new ErrorModel("缺乏文章id"))
} else {
return getDetail(id).then(detailData => {
return new SuccessModel(detailData, '數據獲取成功')
})
}
}
// 新增文章
if (req.method === 'POST' && req.path === '/api/blog/new') {
req.body.author = 'wangwu'
return newBlog(req.body).then(blogId => {
return new SuccessModel(blogId)
})
}
// 文章更新
if (req.method === 'POST' && req.path === '/api/blog/update') {
const id = req.query.id || null
const updateResult = updateBlog(id, req.body)
return updateResult.then(result => {
if (result) {
return new SuccessModel(result, "更新文章成功")
} else {
return new ErrorModel("更新失敗,沒有指定文章id")
}
})
}
// 文章刪除
if (req.method === 'POST' && req.path === '/api/blog/del') {
// 假數據,爲了防止被其餘用戶經過id誤刪文章因此要獲取當前登陸用戶的用戶名
const author = 'lisi'
const id = req.query.id
return delBlog(id, author).then(result => {
if (!result) {
return new ErrorModel("沒有指定刪除的文章id")
}
if (result.affectedRows === 0) {
return new SuccessModel("刪除0條數據")
} else {
return new SuccessModel(result)
}
})
}
}
module.exports = {
handleBlogRouter
}
複製代碼
UserController.js
const { exec } = require('../db/mysql')
const login = (username, password) => {
let sql = `select count(*) as suitRows,username, realname from users where username='${username}' and password = '${password}'`
return exec(sql).then(res => {
return res[0]
})
}
module.exports = {
login
}
複製代碼
router下的user.js
const { login } = require('../controller/UserController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// 登陸
if (req.method === 'POST' && req.path === '/api/user/login') {
const { username, password } = req.body
return login(username, password).then(row => {
if (row.suitRows) {
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
}
module.exports = {
handleUserRouter
}
複製代碼
app.js
const querystring = require('querystring')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') {
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') {
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(
JSON.parse(postData)
)
} else {
resolve({})
return
}
})
})
return promise
}
const serverHandle = (req, res) => {
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
res.setHeader('Content-type', 'application/json')
getPostData(req).then(postData => {
req.body = postData
const blogData = handleBlogRouter(req, res)
if (blogData) {
blogData.then(result => {
if (result) {
res.end(
JSON.stringify(result)
)
}
})
return
}
const userData = handleUserRouter(req, res)
if (userData) {
userData.then(result => {
res.end(
JSON.stringify(result)
)
})
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
})
}
module.exports = serverHandle
複製代碼
nodejs鏈接mysql,執行sql語句
根據NODE_ENV 區分mysql配置
封裝 exec函數,API使用exec函數操做數據庫
核心是登陸校驗和登陸信息存儲
cookie和session
session寫入 redis
開發登陸功能,前端聯調(使用 nginx反向代理)
什麼是cookie,JavaScript操做cookie,瀏覽器中查看cookie
server端操做cookie,實現登陸驗證
存儲在瀏覽器中的一段字符串(最大5kb)
跨域不共享
格式如:k1=v1;k2=v2;k3=v3;所以能夠存儲結構化數據
每次發送http請求,會將請求域的cookie數據一塊發送給server端,好比我在百度請求淘寶的文件,那麼我會將淘寶的cookie數據發送給server端
server能夠修改cookie而且返回給瀏覽器
瀏覽器也能夠經過JavaScript修改cookie(有限制)
查看cookie的方式有不少
一、能夠經過控制檯的Application/Storage/Cookies下查看
二、也能夠經過在控制檯的Network裏面點擊請求的URL,而後查看Request Headers裏面的Cookie
三、還能夠直接在控制檯輸入document.cookie查看當前域下的cookie
document.cookie
複製代碼
四、增長cookie,cookie是累加的模式,會自動在cookie後面接上【注意一次添加一個cookie】
// 客戶端修改cookie,用的很少
document.cookie = "key1=100;"
複製代碼
查看cookie,下面是片斷
// 查看cookie
req.headers.cookie
// cookie提取,轉化
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(";").forEach(element => {
const arr = element.split("=");
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
複製代碼
cd到src目錄,修改app.js,添加上面的部分代碼,完成cookie的解析
const querystring = require('querystring')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') {
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') {
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(
JSON.parse(postData)
)
} else {
resolve({})
return
}
})
})
return promise
}
const serverHandle = (req, res) => {
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(";").forEach(element => {
if (!element) {
return
}
const arr = element.split("=");
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
res.setHeader('Content-type', 'application/json')
getPostData(req).then(postData => {
req.body = postData
const blogData = handleBlogRouter(req, res)
if (blogData) {
blogData.then(result => {
if (result) {
res.end(
JSON.stringify(result)
)
}
})
return
}
const userData = handleUserRouter(req, res)
if (userData) {
userData.then(result => {
res.end(
JSON.stringify(result)
)
})
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
})
}
module.exports = serverHandle
複製代碼
爲了方便直接測試登陸,如今想將登陸換成get請求,這樣能夠在地址欄直接輸入username和password進行登陸
修改user.js
const { login } = require('../controller/UserController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// 登陸
// if (req.method === 'POST' && req.path === '/api/user/login') {
// const { username, password } = req.body
// return login(username, password).then(row => {
// if (row.suitRows) {
// return new SuccessModel(row.realname + "登陸成功")
// } else {
// return new ErrorModel("登陸失敗")
// }
// })
// }
// GET請求,用於測試登陸後 寫入cookie
if (req.method === 'GET' && req.path === '/api/user/login') {
const username = req.query.username
const password = req.query.password
return login(username, password).then(row => {
if (row.suitRows) {
res.setHeader('Set-Cookie', `username=${row.username}; path=/`)
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
if (req.method === 'GET' && req.path === '/api/user/login-test') {
if (req.cookie.username) {
return Promise.resolve(new SuccessModel("已經登錄,登陸用戶名爲" + req.cookie.username))
} else {
return Promise.resolve(new ErrorModel("未登陸"))
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
上面經過獲取地址欄的username和password 去數據庫對比,匹配到的話,使用
res.setHeader('Set-Cookie', `username=${row.username}; path=/`)
複製代碼
設置了cookie,可是這樣不安全,非法用戶仍是能夠經過客戶端修改cookie,好比
// 在控制檯清除掉已經設置的cookie
// 再修改成其餘的cookie
document.cookie="username=lisi"
複製代碼
因此咱們須要在設置cookie的時候加一點東西httpOnly,以下
res.setHeader('Set-Cookie', `username=${row.username}; path=/; httpOnly;`)
複製代碼
最後,cookie通常都最好設置一個過時時間,用來規定這個cookie多久失效
res.setHeader('Set-Cookie', `username=${row.username}; path=/; httpOnly; expires=${getCookieExpires()}`)
const getCookieExpires = (days=1) => {
const d = new Date()
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000))
return d.toGMTString()
}
複製代碼
因此如今完整的user.js文件是這樣的
const { login } = require('../controller/UserController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const getCookieExpires = (days=1) => {
const d = new Date()
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000))
return d.toGMTString()
}
const handleUserRouter = (req, res) => {
// 登陸
// if (req.method === 'POST' && req.path === '/api/user/login') {
// const { username, password } = req.body
// return login(username, password).then(row => {
// if (row.suitRows) {
// return new SuccessModel(row.realname + "登陸成功")
// } else {
// return new ErrorModel("登陸失敗")
// }
// })
// }
// GET請求,用於測試登陸後 寫入cookie
if (req.method === 'GET' && req.path === '/api/user/login') {
const username = req.query.username
const password = req.query.password
return login(username, password).then(row => {
if (row.suitRows) {
res.setHeader('Set-Cookie', `username=${row.username}; path=/; httpOnly; expires=${getCookieExpires(2)};`)
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
if (req.method === 'GET' && req.path === '/api/user/login-test') {
if (req.cookie.username) {
return Promise.resolve(new SuccessModel("已經登錄,登陸用戶名爲" + req.cookie.username))
} else {
return Promise.resolve(new ErrorModel("未登陸"))
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
cookie會暴露username,很危險
如何解決:cookie中存儲userid,server端利用這個userid對應的查出登陸後的一些用戶信息
server端比較安全,並且空間大一些。cookie只有5kb的存儲空間
解決方案:session存儲用戶信息
思路:定義一個全局的對象SESSION_DATA = {}; 每次調用接口的時候,判斷cookie是否有有userid這個key,若是沒有,隨機生成一個userid而後保存到cookie中。若是有了的話,SESSION_DATA[userId] = {}, req.session = SESSION_DATA[userid],登陸成功以後,將登陸信息設置到req.session中,如req.session.username = rows[0].username
app.js
const querystring = require('querystring')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
// session數據
const SESSION_DATA = {}
// 設置cookie的過時時間
const getCookieExpires = (days=1) => {
const d = new Date()
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000))
return d.toGMTString()
}
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') {
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') {
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(
JSON.parse(postData)
)
} else {
resolve({})
return
}
})
})
return promise
}
const serverHandle = (req, res) => {
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(";").forEach(element => {
if (!element) {
return
}
const arr = element.split("=");
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
// 標誌,規定是否須要設置cookie
let needSetCookie = false
// 解析cookie後,提取裏面的userid出來保存起來
let userId = req.cookie.userid
if (!userId) {
// 若是userid不存在,那麼規定等下須要設置cookie,而且把要設定的cookie的值隨機生成好
needSetCookie = true
userId = `${Date.now()}_${Math.random()}`
SESSION_DATA[userId] = {}
} else {
// 若是有userid這個cookie,那麼
if (!SESSION_DATA[userId]) {
SESSION_DATA[userId] = {}
}
}
req.session = SESSION_DATA[userId]
res.setHeader('Content-type', 'application/json')
getPostData(req).then(postData => {
req.body = postData
const blogData = handleBlogRouter(req, res)
if (blogData) {
blogData.then(result => {
// 請求返回的時候,判斷是否須要設置cookie
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
if (result) {
res.end(
JSON.stringify(result)
)
}
})
return
}
const userData = handleUserRouter(req, res)
if (userData) {
userData.then(result => {
// 請求返回的時候,判斷是否須要設置cookie
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(result)
)
})
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
})
}
module.exports = serverHandle
複製代碼
user.js
const { login } = require('../controller/UserController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// GET請求,用於測試登陸後 寫入cookie
if (req.method === 'GET' && req.path === '/api/user/login') {
const username = req.query.username
const password = req.query.password
return login(username, password).then(row => {
if (row.suitRows) {
// 若是帳號密碼匹配成功,那麼將用戶信息保存到對應cookie裏userid的req.session中
req.session.username = row.username
req.session.realname = row.realname
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
if (req.method === 'GET' && req.path === '/api/user/login-test') {
if (req.session.username) {
return Promise.resolve(new SuccessModel("已經登錄,真名爲" + req.session.realname))
} else {
return Promise.resolve(new ErrorModel("未登陸"))
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
可是!!! session的問題也是存在的
session直接是js變量,放在nodejs進程內存中,可是進程內存有限,訪問量過大,內存暴漲確定不行;還有正式上線以後,運行的是多進程,進程之間內存沒法共享
解決方案: redis
redis是web server最經常使用的緩存數據庫,數據存放在內存中,優勢是讀取快,缺點是內存昂貴有限,斷電數據丟失。相比於mysql,redis更快更強,畢竟硬盤速度方面幹不過內存。
在現實的開發中,通常把redis和mysql結合使用,互相搭配,幹活不累
爲何session和redis那麼適合在一塊兒?
session訪問頻繁,對性能要求極高,而redis很合適。
session能夠不考慮斷電丟失數據的問題
session的數據不會特別大, 通常在內存的控制範圍
爲何網站數據不適合用redis
由於操做頻率不是很高
斷電後數據不可以丟失!!!
數據量比較大,內存成本過高
mac:
brew install redis
複製代碼
windows:www.runoob.com/redis/redis…
下載完redis壓縮包以後,解壓,而後將文件夾改名爲redis,放入c盤(最好去環境變量添加一下)。而後在命令行進入到該目錄下執行命令
redis-server.exe
複製代碼
這樣的話redis服務端就已經啓動了
這時候不要關閉原來的服務端窗口,另外打開一個cmd窗口,進入到redis目錄下,執行命令。
redis-cli.exe -h 127.0.0.1 -p 6379
複製代碼
redis是利用set和get和del來操做鍵值對的。因此能夠利用
// 在redis裏存儲key1值爲val1
set key1 val1
// 在redis裏獲取key1的值
get key1
set key2 val2
// 刪除key1
del key1
列出全部key
keys *
複製代碼
mkdir redis-test && cd redis-test
npm init -y
type nul>index.js
npm install redis --save-dev
複製代碼
redis-test下的index.js
// 引入安裝好的redis
const redis = require('redis')
// 建立redis客戶端
const redisClient = redis.createClient(6379, '127.0.0.1')
// 監聽錯誤
redisClient.on('error', err => {
console.error(err)
})
// set方法設置值,redis.print參數表示要打印出設置的狀態
redisClient.set("myname", "zhangsan", redis.print)
// get方法讀取值,是一個異步過程,後續須要封裝進promise裏面
redisClient.get("myname", (err, val) => {
if (err) {
console.log(err)
return
}
console.log('val:' + val)
// 退出
redisClient.quit()
})
複製代碼
還能夠存儲對象形式的,改進以後的index.js
const redis = require('redis')
const redisClient = redis.createClient(6379, '127.0.0.1')
redisClient.on('error', err => {
console.error(err)
})
const session = {
username: 'lzx',
realname: '小羅羅'
}
const sessionStr = JSON.stringify(session)
redisClient.set("mysession", sessionStr, redis.print)
redisClient.get("mysession", (err, val) => {
if (err) {
console.log(err)
return
}
console.log('username:' + JSON.parse(val).username)
console.log('realname:' + JSON.parse(val).realname)
redisClient.quit()
})
複製代碼
node index.js
複製代碼
cd到blog-01
npm install redis --save-dev
複製代碼
進入src/conf下的db.js,咱們配置一下redis的配置參數
const env = process.env.NODE_ENV
let MYSQL_CONF
// 定義redis配置變量
let REDIS_CONF
if (env === 'dev') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
}
// 開發環境下的端口和主機
REDIS_CONF = {
port: 6379,
host: '127.0.0.1'
}
}
if (env === 'production') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
}
// 生產環境下的端口和主機(暫不改動)
REDIS_CONF = {
port: 6379,
host: '127.0.0.1'
}
}
module.exports = {
MYSQL_CONF,
// 導出
REDIS_CONF
}
複製代碼
cd到src/db目錄
type nul>redis.js
複製代碼
redis.js
const redis = require('redis')
const { REDIS_CONF } = require('../conf/db')
const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)
redisClient.on('error', (err) => {
console.log(err)
})
function set(key, val) {
if (typeof val === 'object') {
val = JSON.stringify(val)
}
redisClient.set(key, val, redis.print)
}
function get(key) {
const promise = new Promise((resolve, reject) => {
redisClient.get(key, (err, val) => {
if (err) {
reject(err)
return
}
if (val === null) {
resolve(null)
return
}
try {
resolve(
JSON.parse(val)
)
} catch (error) {
resolve(val)
}
})
})
return promise
}
module.exports = {
set,
get
}
複製代碼
app.js
const querystring = require('querystring')
// 引入redis的設置和讀取方法
const { set, get } = require('./src/db/redis')
const { handleBlogRouter } = require('./src/router/blog')
const { handleUserRouter } = require('./src/router/user')
const getCookieExpires = (days=1) => {
const d = new Date()
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000))
return d.toGMTString()
}
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if (req.method !== 'POST') {
resolve({})
return
}
if (req.headers['content-type'] !== 'application/json') {
resolve({})
return
}
let postData = ''
req.on('data', chunk => {
postData += chunk.toString()
})
req.on('end', () => {
if (postData) {
resolve(
JSON.parse(postData)
)
} else {
resolve({})
return
}
})
})
return promise
}
const serverHandle = (req, res) => {
res.setHeader('Content-type', 'application/json')
req.path = req.url.split('?')[0]
req.query = querystring.parse(req.url.split('?')[1])
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(";").forEach(element => {
if (!element) {
return
}
const arr = element.split("=");
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
let needSetCookie = false
let userId = req.cookie.userid
if (!userId) {
// 若是沒有userid這個cookie
needSetCookie = true
userId = `${Date.now()}_${Math.random()}`
// 若是沒有名爲userid的cookie,那麼將空對象賦值給一個隨機值key,而後寫入redis庫
set(userId, {})
}
req.sessionId = userId
// 從redis中讀取key爲req.cookie.userid對應的值或者剛產生的隨機值userId做爲key所對應的值
get(req.sessionId).then(sessionData => {
if (sessionData === null) {
req.session = {}
set(req.sessionId, {})
} else {
// 若是值不爲空,那麼設置到session中,方便後續login-test讀取
req.session = sessionData
}
// 當req.session賦值完成時,開始獲取post的數據,該方法是返回一個promise
return getPostData(req)
})
.then(postData => {
req.body = postData
const blogData = handleBlogRouter(req, res)
if (blogData) {
blogData.then(result => {
// 若是當前沒有cookie,那麼設置一下
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
if (result) {
res.end(
JSON.stringify(result)
)
}
})
return
}
const userData = handleUserRouter(req, res)
if (userData) {
userData.then(result => {
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(result)
)
})
return
}
// 未命中路由
res.writeHead(404, {"Content-type": "text/plain"})
res.write("404 Not Found!!\n")
res.end()
})
}
module.exports = serverHandle
複製代碼
user.js
const { login } = require('../controller/UserController')
// 引入寫入redis的方法
const { set } = require('../db/redis')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// GET請求,用於測試登陸後 寫入cookie
if (req.method === 'GET' && req.path === '/api/user/login') {
const username = req.query.username
const password = req.query.password
return login(username, password).then(row => {
if (row.suitRows) {
req.session.username = row.username
req.session.realname = row.realname
// 將req.session設置到 redis中保存起來(同步到redis)
set(req.sessionId, req.session)
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
if (req.method === 'GET' && req.path === '/api/user/login-test') {
if (req.session.username) {
return Promise.resolve(new SuccessModel("已經登錄,真名爲" + req.session.realname))
} else {
return Promise.resolve(new ErrorModel("未登陸"))
}
}
}
module.exports = {
handleUserRouter
}
複製代碼
在login-test中,經過req.session.username來判斷是否已經登陸。若是刪掉了cookie,從新渲染時,那麼req.sessionId會發生改變,而後登陸信息req.session也會被初始化爲空對象。那麼就至關於退出了登陸狀態。
由於如今已經能夠經過req.session.username的真假來判斷是否已經登陸,好比在進入新建博客頁面,修改博客頁面,刪除博客頁面以前,都要校驗一下是否已經登陸,若是沒登陸, 應該返回什麼信息而且拒絕接下來的操做。這個項目主要是blog路由的校驗,因此咱們能夠定義個函數來處理這部分的校驗
// 統一的登陸驗證函數
const loginCheck = (req) => {
if (!req.session.username) {
return Promise.resolve(
new ErrorModel('還沒有登陸')
)
}
}
複製代碼
修改一下blog.js
const { getList, getDetail, newBlog, updateBlog, delBlog } = require('../controller/BlogController')
const { SuccessModel, ErrorModel } = require('../model/resModel')
// 登陸校驗函數
const loginCheck = (req) => {
if (!req.session.username) {
return Promise.resolve(
new ErrorModel('還沒有登陸')
)
}
}
const handleBlogRouter = (req, res) => {
// 獲取博客列表
if (req.method === 'GET' && req.path === '/api/blog/list') {
const author = req.query.author || ''
const keyword = req.query.keyword || ''
return getList(author, keyword).then(listData => {
return new SuccessModel(listData, '數據獲取成功')
})
}
// 獲取博客內容
if (req.method === 'GET' && req.path === '/api/blog/detail') {
const id = req.query.id || null
if (id === null) {
return new Promise((resolve) => {
resolve(false)
}).then(() => new ErrorModel("缺乏文章id"))
} else {
return getDetail(id).then(detailData => {
return new SuccessModel(detailData, '數據獲取成功')
})
}
}
// 新增文章
if (req.method === 'POST' && req.path === '/api/blog/new') {
const loginCheckResult = loginCheck(req)
if (!!loginCheckResult) {
// 未登陸
return loginCheck(req)
}
req.body.author = req.session.username
return newBlog(req.body).then(blogId => {
return new SuccessModel(blogId)
})
}
// 文章更新
if (req.method === 'POST' && req.path === '/api/blog/update') {
const loginCheckResult = loginCheck(req)
if (!!loginCheckResult) {
// 未登陸
return loginCheck(req)
}
const id = req.query.id || null
const updateResult = updateBlog(id, req.body)
return updateResult.then(result => {
if (result) {
return new SuccessModel(result, "更新文章成功")
} else {
return new ErrorModel("更新失敗,沒有指定文章id")
}
})
}
// 文章刪除
if (req.method === 'POST' && req.path === '/api/blog/del') {
const loginCheckResult = loginCheck(req)
if (!!loginCheckResult) {
// 未登陸
return loginCheck(req)
}
// 假數據,爲了防止被其餘用戶經過id誤刪文章因此要獲取當前登陸用戶的用戶名
const author = req.session.username
const id = req.query.id
return delBlog(id, author).then(result => {
if (!result) {
return new ErrorModel("沒有指定刪除的文章id")
}
if (result.affectedRows === 0) {
return new SuccessModel("刪除0條數據")
} else {
return new SuccessModel(result)
}
})
}
}
module.exports = {
handleBlogRouter
}
複製代碼
修改一下user.js,將login-test去掉,而且把login爲GET改回POST
const { login } = require('../controller/UserController')
const { set } = require('../db/redis')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
// 登陸
if (req.method === 'POST' && req.path === '/api/user/login') {
const { username, password } = req.body
return login(username, password).then(row => {
if (row.suitRows) {
req.session.username = row.username
req.session.realname = row.realname
set(req.sessionId, req.session)
return new SuccessModel(row.realname + "登陸成功")
} else {
return new ErrorModel("登陸失敗")
}
})
}
}
module.exports = {
handleUserRouter
}
複製代碼
至此,接口已經完成了。接下來就是與前端頁面的聯調了
由於cookie跨域不共享,因此前端和server端必需要同域
須要用nignx作代理,讓先後端同域
在blog-01的所在目錄下
複製代碼
安裝http-server
npm install http-server -g
http-server -p 8001
複製代碼
把你的靜態頁面index.html放到http-server中,就能夠打開http://192.168.1.50:8001/index.html進行訪問了
高性能web服務器,開源免費
通常用於作靜態服務,負載均衡(暫時用不到)
反向代理:遇到/...就代理到html的服務器上,而遇到/api/...就代理到node.js服務器
mac: brew install nginx
windows: nginx.org/en/download…
下載最新版本的或者穩定版本的
下載完成以後解壓裏面的內容到c盤的nginx目錄下,添加一下環境變量
而後操做的時候cd到nginx目錄操做
window: c:\nginx\conf\nginx.conf
mac:/usr/local/etc/nginx/nginx.conf
mac下
測試配置文件格式是否正確 nginx -t
啓動:nginx; 重啓:nginx -s reload;中止: nginx -s stop
windows下,須要cd到nginx目錄下
啓動:start nginx
測試:nginx -t
mac
sudo vi /usr/local/etc/nginx/nginx.conf
複製代碼
windows直接用管理員權限打開文件nginx/nginx.conf記事本
第三行:
// 用雙核,不寫默認是單核
worker-processes 2;
複製代碼
找到server{},監聽這個端口
listen 8080;
複製代碼
找到location,用#號註釋,而後本身寫代理
// 若是是/... 代理到http://localhost:8000
location / {
proxy_pass http://localhost:8001;
}
// 若是是/api/... 代理到http://localhost:3000
location /api/ {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
}
複製代碼
測試:
nginx -t
// 返回is ok 和 is successful 就代表沒有問題
// 語法沒問題就直接啓動,mac下直接使用nginx執行
nginx
// -------------windows
// 測試
nginx -t
// 啓動
start nginx
// 重載
nginx -s reload
// 中止
nginx -s stop
複製代碼