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
复制代码