共计 6943 个字符,预计需要花费 18 分钟才能阅读完成。
二、node 的简介
node 是一个运行 js 的环境。浏览器也是运行 js 的环境。
两者的差别在于:
- 浏览器会有 window 和 document 的调用。然而 node 没有
- node 有许多模块的 api,例如文件系统拜访性能
- node 能够切换运行环境(切换版本?)
- node 不必 bable 转换
- node 应用的是 commonJS,要应用 require
2-2 nodejs 与 js 的区别
nodejs = nodejsapi + ecmascript
解决 http,解决文件等。
2-3 commonjs
module.export()
require
2-4,5 debuger 之 inspect 协定
--inspect==9229
chrome://inspect/#devices
四、开发博客我的项目之接口
4-1 http 概述
从 url 到浏览器的过程?
首先 dns 解析,解析完了发送申请,通过 http 协定建设 tcp 链接,而后传输文件。
浏览器拿到数据而后建设 dom 树,建设 css 树。合并成 render 树,而后渲染,注入 js。DNS 解析,建设 TCP 连贯,发送 http 申请
server 接管到 http 申请,解决并返回。
客户端接管到返回数据,解决数据,(如渲染页面,执行 js)
Remote address 就是 dns 查问的后果
4-4 解决 http 申请的综合示例
const http = require("http");
const port = 3000
const server = http.createServer((req, res) => {res.setHeader("Content-Type", "application/json")
const url = req.url
const method = req.method
res.end(`${url}${method}`);
})
server.listen(port, () => {console.log(` 服务器运行在 http://localhost:${port}/`)
})
console.log("ok")
4-5 搭建开发环境
- 应用 nodemon 检测文件变动,主动重启 node。
- corss-env 设置环境变量
npm i nodemon cross-env --save-dev
"scripts": {
"test": "echo \"Error: no test specified\"&& exit 1",
"dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js"
},
4-6 初始化路由
hostname:nodejs.cn
pathname:/api/blog/list
query:?name=zhangsan&keyword=123
const method = res.method // post get
const url = res.url // url
const path = res.url.split("?")[0] //
4-7 开发路由
创立SuccessModel
、ErrorModel
。
class BaseModel {constructor(data, message) {if (typeof data === "string") {
this.message = data;
message = null;
data = null
}
if (data) {this.data = data;}
if (message) {this.message = message;}
}
}
class SuccessModel extends BaseModel {constructor(data, message) {super(data, message);
this.error = 0
}
}
class ErrorModel extends BaseModel {constructor(data, message) {super(data, message);
this.error = -1
}
}
module.exports = {
SuccessModel,
ErrorModel
}
4-8 开发路由(博客详情路由)
const fs = require('fs');
const path = require('path');
function getFileContent(fileName) {const fullFileName = path.resolve(__dirname, 'file', fileName)
const promise = new Promise((resolve, reject) => {fs.readFile(fullFileName, (err, data) => {if (err) {reject(err);
}
resolve(JSON.parse(data));
})
})
return promise;
}
getFileContent('a.json').then(aDate => {console.log(aDate);
return getFileContent(aDate.next);
}).then((bData) => {console.log(bData);
return getFileContent(bData.next);
}).then((cData) => {console.log(cData);
});
4-9 开发路由(解决 POSTData)
// 用于解决 post data
const getPostData = (req) => {const promise = new Promise(() => {if (req.method !== 'POST') {resolve({})
return
}
if (req.headers['content-type'] !== "application/json") {resolve({})
return
}
})
// 监听流数据
let postData = ''res.on('data', chunk => {postData += chunk.toString()
})
res.on('end', () => {if (!postData) {resolve({})
return
}
resolve(JSON.parse(postData)
)
})
return promise
}
更新和删除数据等 ….
5 数据库
MySql
use myblog;
-- 查表
-- show tables;
-- insert into blogs(title,content,createtime,author)values("市民胡女士 2 的题目","市民胡女士 2 的内容",1585645673144,"mjmjmj");
SELECT * FROM myblog.users LIMIT 0,1000;
-- select username from users;
-- select * from users where password like '%1%' order by id desc;
-- select * from blogs;
-- ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password' PASSWORD EXPIRE NEVER;
-- ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '11111111';
-- flush privileges
-- insert into blogs (title, content, createtime, author)values ('hhhhhh', 'jjhhhhh', 1585646800912, 'mjmjmj');
-- select username, realname from users where username='mjmjmj' and password='321654a.'
-- 更新
-- SET SQL_SAFE_UPDATES = 0;
-- update users set state = 0;
-- update users set username ='huhuhu' where id = '2';
-- 删除
-- delete from blogs where id='1';
5.4 nodejs 操作 数据库
const mysql = require('mysql');
const con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '11111111',
port: '3306',
database: 'myblog',
})
// 开始连贯
con.connect()
// 执行 sql
const sql = 'select * from users;';
con.query(sql, (err, result) => {if (err) {console.log(err);
return;
}
console.log(result);
})
con.end();
const mysql = require('mysql');
const {MYSQL_CONF} = require("../conf/db");
// 创立链接对象
const con = mysql.createConnection(MYSQL_CONF);
// 建设连贯
con.connect();
// 对立执行 sql 的函数
function exec(sql) {const promise = new Promise((resolve, reject) => {con.query(sql, (err, result) => {if (err) {reject(err);
return
}
resolve(result)
})
})
return promise;
}
con.end();
module.exports = {exec}
6.2 Cookie 介绍
什么是 cookie?
js 如何操作 cookie,如何在浏览器中查看 cookie?
server 端操作 cookie,实现登录验证、
特点:
- 最大 5kb
- 跨域不共享,
- 可保留结构化数据
- 每次发送 http 申请,会将申请域的 cookoie 一起发送给 cookie
- server 端能够批改 cookie,并返回给客户端
- 客户端也能够通过 js 批改 cookie,并返回给 server 端(有限度)
- 看申请的哪个域,申请哪个域,带哪个 cookie
申请头外部的 cookie
本地的缓存 cookie
domin:cookie 失效的域名
path: 是 cookie 失效门路
批改 cookie
有了 localStorage,本地批改 cookie 的状况不多
nodejs 批改 cookie
// 解析 cookie
req.cookie = {}
const cookieStr = req.headers.cookie || '' // k1=v1;k2=v2;k3=v3
cookieStr.split(';').forEach(item => {if (!item) {return}
const arr = item.split('=')
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
nodejs setCookie
// 登录
if (method === 'POST' && req.path === '/api/user/login') {const { username, password} = req?.body
const result = login(username, password)
return result.then(data => {if (data.username) {
// 操作 cookie
res.setHeader('SetCookie', `username=${data.username}`)
return new SuccessModel()}
return new ErrorModel('登录失败')
})
}
6.4 cookie 做限度
设置 httpOnly
res.setHeader('SetCookie', `username=${data.username}; path=/; httpOnly`)
// 获取 cookie 的过期工夫
const getCookieExpires = () => {const d = new Date()
d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
console.log('d.toGMTString() is', d.toGMTString())
return d.toGMTString()}
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
6.6 session
cookie 中 会裸露 username,很危险userid
、sid
、conentid
, 对应 server 端 username.
- session 间接是 js 变量,放在 nodejs 过程内存中;
- 内存过大,会把过程的空间挤爆
- 多过程之间,数据无奈共享
6.8 redis
redis 解决 多过程
不可能互通 session
的问题(挤爆,多过程之间无奈数据共享。),是服务端罕用的缓存工具。
web server
最罕用的缓存数据库,数据寄存在内存中,相比 mysql 读写速度快,然而比拟低廉,断电失落。
- 独自的服务,与 nodejs 之间只是调用关系。就像 mysql 一样,所以不存在被挤爆的状况。
- 多过程之间拜访同一个 redis。所以 session 会同步。
- redis 可拓展,就算用户量减少,那也能够减少机器,能够拓展成集群。
session 对性能的要求极高
,因为每次都会发送申请。断电失落没关系,从新登录即可。所以不可能间接存在 mysql 中。
6.9
const redis = require('redis');
const {REDIS_CONF} = require('../conf/db');
// 创立客户端
const redisClient = redis.createClient(REDIS_CONF);
redisClient.on('error', (error) => {console.log(error);
})
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 (ex) {resolve(val)
}
resolve(val);
})
});
return promise;
}
module.exports = {
set,
get
}
set myname mj
get myname // mj
get * // 获取所有 key value
// 获取 session
req.sessionId = userId
get(req.sessionId).then(sessionData => {if (sessionData == null) {
// 初始化 redis 中的 session 值
set(req.sessionId, {})
// 设置 session
req.session = {}} else {
// 设置 session
req.session = sessionData
}
// console.log('req.session', req.session)
// 解决 post data
return getPostData(req)
})
.then(postData => {......}
6.14 为什么应用 nginx
因为前端起的一个服务和 nodejs 起的服务不是同一个端口,而 cookie 跨域不共享。
应用 http-server 起一个前端的服务。端口设置为 8001。
nodejs:8000 端口
大家都去 8080 端口。
6.15 高性能的 web 服务器 nginx),开源,收费
如果申请 /
根目录,申请 html,那么,nginx 间接返回返回 html
如果申请 /api/blog/...
先到 nginx 端口 8000,而后再到 node 服务的端口,8001.
对客户端不可见的代理,称为 反向代理
应用 easyconnect 连贯,被称为 正向代理
,客户端能够管制
- 测试配置文件格式是否正确:
ngnix -t
- 启动 nginx 重启 nginx -s reload
- 进行 ngnix -s stop
sudo vi /usr/local/etc/nginx/nginx.conf
次要就是增加这些代码,而后把下面的一些正文掉。
location / {proxy_pass <http://localhost:8001>;}
location /api/{
proxy_pass <http://localhost:8000>;
proxy_set_header Host $host;
}
感觉搞了半天,就是看懂了什么是 redis,什么是 session,什么是 ngnix,代码外面就是配一配。