node中的模块导入和导出
在node中使用
module.exports导出一个模块在node中使用
require导入一个模块 ```javascript function add(a,b){ return a+b; } module.exports = add//导出一个模块
const add=require(“./index”)//导入一个模块,其中require是一个函数,接收一个路径作为参数 const sum=add(10,20); console.log(sum)
//在导入模块的过程中可以按需导入,前提是导出的是一个对象=>es6中的解构赋值 const {name,add}=require(“./index”)
<a name="fae773c5"></a>### 在node中创建一个http服务-通过`http`模块创建一个http服务```javascript//http.createServer创建一个http服务//获取请求头req.headers["content-type"]const server=http.createServer((req,res)=>{// writeHead()方法用于设置响应数据的响应头headers//第一个参数为响应的状态码,第二个参数为响应头res.writeHead(200,{"content-type":"text/html"})//设置响应数据的响应头res.end("<h1>hello word</h1>")//发送响应信息})//监听一个3000端口server.listen(3000,()=>{console.log("创建一个http服务成功")})
- 处理get请求 ```javascript const http = require(“http”); const querystring = require(“querystring”);
const server=http.createServer((req,res)=>{ console.log(req.method)//返回请求的方式 const url=req.url; console.log(“请求的url地址:”+url); req.query=querystring.parse(url.split(“?”)[1])//parse默认使用&分割查询字符串 console.log(req.query) res.end( JSON.stringify(req.query)//向前端返回json格式的数据 ) }) server.listen(3000,()=>{ console.log(“创建服务成功”) })
-处理post请求```javascriptconst http = require("http");const server=http.createServer((req,res)=>{if(req.method==='POST'){//req的数据格式console.log("req content-type:"+req.headers['content-type'])}//接收到的数据let postData="";//监听请求数据的发送req.on("data",chunk=>{postData+=chunk.toString();})//监听数据发送结束req.on("end",()=>{console.log(postData)res.end("请求发送成功")})})server.listen(3000)
- node综合处理get和post请求 ```javascript const http = require(“http”); const querystring = require(“querystring”);
const server=http.createServer((req,res)=>{ const method=req.method;//获取请求的方式
const url=req.url;//获取前端请求的url地址
const path=url.split(“?”)[0]//获取前端的网页地址
const query=querystring.parse(url.split(“?”)[1])//获取查询字符串
//设置返回的数据为json
//设置响应数据的响应头 res.setHeader(“Content-type”,”application/json”); //返回的数据 const resData={ method,url,path,query }
if(method==='GET'){res.end(JSON.stringify(resData)//设置返回字符串的格式)}else if(method==='POST'){let postData=""//监听前端发送过来的数据,当前端有数据发送过来时,传递给chunkreq.on("data",(chunk)=>{postData=chunk.toString()})//监听前端发送数据结束,执行回调函数req.on("end",()=>{resData.postData=postData;res.end(JSON.stringify(resData)//设置返回字符串的格式)})}
}) server.listen(3000)
<a name="202459f0"></a>### nodemon使用-nodemon检测文件变化,自动重启node```javascript//安装nodemon cnpm i nodemon -g//安装cross-env cnpm i cross-env -S//配置"scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev":"cross-env NODE_ENV=dev nodemon ./bin/www.js","prd":"cross-env NODE_ENV=production nodemon ./bin/www.js"}//创建响应文件 ./bin/www.js
cross-env是用来设置不同的运行环境
node中的cookie和session
cookie
- 存储在浏览器中的一段字符串(最大5kb)
- 跨域不共享
server操作cookie
//获取cookie//解析cookiereq.cookie={}const cookieStr=req.headers.cookie||""//cookie的格式是k1=1;k2=2;k3=3cookieStr.split(";").forEach(item=>{if(!item){return}const arr=item.split("=")const key=arr[0]const val=arr[1]req.cookie[key]=val})//设置cookie的值,path参数表示这个cookie可以在所有的网页都能访问,httpOnly参数限制cookie不能修改//expires参数设置cookie的过期时间const getCookieExpire = () => {const d = new Date();d.setTime(d.getTime() + (24 * 60 * 60 * 1000))return d.toGMTString();}res.setHeader("Set-Cookie", `username=${data.username};path=/;httpOnly;expires=${getCookieExpire()}`)
session
const SESSION_DATA = {}//解析sessionlet needSetCookie=false//标志userid是否已经存在let userId = req.cookie.useridif (userId) {if (!SESSION_DATA[userId]) {SESSION_DATA[userId] = {}}}else {needSetCookie=trueuserId = `${Date.now()}_${Math.random()}`SESSION_DATA[userId] = {}}req.session = SESSION_DATA[userId]//设置数据req.session.username=data.username;req.session.realName=data.realName;
redis
web server最常用的缓存数据库,数据存放在内存中
相比于mysql,访问速度快(内存和硬盘不是一个数量级的)
成本高,可存储的数据量小
安装redis
https://github.com/microsoftarchive/redis/releases启动redis
- 打开一个cmd窗口进入redis安装目录
redis-server.exe redis.windows.conf - 在redis目录下再打开一个cmd
redis-cli.exe -h 127.0.0.1 -p 6379
- 打开一个cmd窗口进入redis安装目录
node中使用redis
- 安装redis
cnpm i redis -S
//导入redis模块const redis=require("redis")//创建redis客户端 端口对应redis启动时的端口号const redisClient=redis.createClient(6379,"127.0.0.1")//监听redis客户端是否发生异常redisClient.on("error",err=>{console.log(err)})//测试 redis.print设置了这个参数会打印出设置是否成功//向redis中添加数据redisClient.set("myname","张三",redis.print)//获取redis中的数据redisClient.get("myname",(err,val)=>{if(err){return console.log(err)}console.log(val)//退出redisClient.quit()})
- 对获取数据和设置数据的封装
```javascript
function set(key, val) {
//测试 redis.print设置了这个参数会打印出设置是否成功
if (typeof val === ‘object’) {
} redisClient.set(key, val, redis.print) }val = JSON.stringify(val)
function get(key) { return new Promise((resolve, reject) => { redisClient.get(key, (err, val) => { if (err) { return reject(err) }
if (val == null) {return resolve(null)}try {resolve(JSON.parse(val))} catch (error) {resolve(val)}})})
}
<a name="nginx"></a>### nginx-[基本使用方式](https://blog.csdn.net/u011418717/article/details/52776090)-高性能的web服务器,开源免费-一般用于做静态服务,负载均衡-反向代理(对客户端不可见的代理,实现前后端跨域访问)-测试配置文件格式是否正确`nginx -t`-启动`start nginx`,重启`nginx -s reload`-停止`nginx -s stop`-配置```javascript//通过server属性配置多个服务器的地址,当一个服务器不能使用,nginx自动检索下一个upstream local_tomcat {server localhost:8001;server localhost:4000;}server {listen 8080;//nginx服务器的端口号server_name localhost;location /{proxy_pass http://localhost:8001;//当访问127.0.0.1:8080/时nginx服务器代理默认跳到http://localhost:8001#proxy_pass http://local_tomcat =>upstream的使用}location /api/{proxy_pass http://localhost:8000;//当访问127.0.0.1:8080/api/时nginx服务器代理默认跳到http://localhost:8000proxy_set_header Host $host;//由于访问的地址是localhost:8080/api/...,而实际需要访问的地址是http://localhost:8000/api/...,两个的请求头localhost:8080(localhost:8000)不相同,如果后端设置有请求头限制比如只能访问localhost:8000,那么就会报错,所以设置proxy_set_header Host $host就是为了当在向后端发送请求时,指定请求头为 proxy_pass指定的值}}
node操作文件
- 读取文件
//读取文件的模块const fs=require("fs")//拼接文件路径的模块const path=require("path")//用于拼接路径,由于不能的系统路径不一样,因此使用这个模块,能够保证路径的统一const filename=path.resolve(__dirname,"data.txt")//获取当前目录下的data.txt文件的路径名//读取文件内容//参数1为文件的路径,参数2为回调函数fs.readFile(filename,(err,data)=>{if(err){return console.log(err)}console.log(data.toString())})
- 写入文件
const fs=require("fs")const path=require("path")//用于拼接路径,由于不能的系统路径不一样,因此使用这个模块,能够保证路径的统一const filename=path.resolve(__dirname,"data.txt")//获取当前目录下的data.txt文件的路径名//写入文件const content="11111111111111111111111111111111"const opt={flag:'a',//追加写入,覆盖用'w'}//参数1是写入文件的路径,//参数2为向文件写入的内容,//参数3为写入的方式,a表示追加写入,w覆盖写入//参数4是一个回调函数fs.writeFile(filename,content,opt,(err)=>{if(err){return console.log(err)}})
- 判断文件是否存在
//判断文件是否存在fs.exists(filename,(exist)=>{console.log(exist)//文件存在返回true,否则为false})
- stream操作文件
const fs = require("fs")const path = require("path")//被读取的文件路径const filename1 = path.resolve(__dirname, "data1.txt")//写入内容的文件路径const filename2 = path.resolve(__dirname, "data2.txt")//读取文件的stream对象const readStream = fs.createReadStream(filename1);//写入文件的stream对象const writeStream = fs.createWriteStream(filename2);//执行拷贝,通过pipereadStream.pipe(writeStream);//拷贝结束readStream.on("end",(err)=>{if(err){console.log(err)}})
- 请求读取文件
const path=require("path")const fs=require("fs")const http=require("http")const filename1 = path.resolve(__dirname, "data1.txt")const filename2 = path.resolve(__dirname, "data2.txt")http.createServer((req,res)=>{if(req.method==="POST"){let postData="";req.on("data",chuck=>{postData=chuck.toString();//json格式的字符串})req.on("end",()=>{postData=JSON.parse(postData)if(postData.filename==="data1"){//读取文件的stream对象const readStream = fs.createReadStream(filename1);readStream.pipe(res)}else{//读取文件的stream对象const readStream = fs.createReadStream(filename2);readStream.pipe(res)}})}}).listen(8000)
- node向文件中写日志
const fs=require("fs")const path=require("path")//写日志function writeLog(writeStream,log){writeStream.write(log+"\n")}//生成write Streamfunction createWriteStream(fileName){//日志文件的存储地址const fullFileName=path.resolve(__dirname,"../","../","logs",fileName)const writeStream=fs.createWriteStream(fullFileName,{flags:'a'})return writeStream;}//写访问日志const accessWriteStream=createWriteStream('access.log')function access(log){writeLog(accessWriteStream,log)}module.exports={access}
node中的md5加密
const crypto=require("crypto");//密匙const SECRET_KEY="123456"//md5加密function md5(content){let md5=crypto.createHash("md5");//创建一个hash对象,创建hash对象使用的算法是md5//md5.update(content)使用给定的content更新hash对象的内容,.digest("hex")使用相应的字符编码返回hash值return md5.update(content).digest("hex")}//加密函数function getPassword(password){const str=`password=${password}&key=${SECRET_KEY}`return md5(str)}console.log(getPassword(123))
node中连接数据库
安装mysql模块
cnpm i mysql -S-
//导入mysql模块const mysql=require("mysql")//创建数据库连接对象const conn=mysql.createConnection({host:"localtion",host:"localhost",//数据库连接的ip地址user:"root",//连接数据库的用户名password:"root",//连接数据库的密码port:"3306",//数据库的端口号database:"myblog"//数据库的名称})//开始连接数据库conn.connect((err)=>{if(err)console.log(err)})//封装的一个进行增删改查的函数function exec(sql){return new Promise((resolve,reject)=>{con.query(sql,(err,result)=>{if(err){return reject(err)}resolve(result)})})}
express框架
安装express
cnpm i express-generator -g //安装express脚手架express express-test //创建express应用npm start //运行应用
中间件
- 使用
app.use()注册中间件 next()上一个中间件触发下一个中间件
const express = require('express');const cookieParser = require('cookie-parser');const app=express()//处理表单提交数据,将处理后的数据挂载到req.body中app.use(express.urlencoded({ extended: false }))//处理json格式的数据app.use(express.json())//处理cookieapp.use(cookieParser())//创建一个路由const router=express.Router();//注册路由const blogRouter = require('./routes/blog');app.use('/api/blog', blogRouter);//通过express-session处理session数据//安装 cnpm i express-session -S//注册const session =require("express-session")var cookieParser = require('cookie-parser');app.use(cookieParser());app.use(session({secret:"qwe",cookie:{path:"/",//任意路径都能访问httpOnly:true,//是否允许修改maxAge:24*60*60*1000//过期时间}}))//获取sessionreq.session
- 路由 ```javascript var express = require(‘express’); var router = express.Router();
router.get(‘/list’, function (req, res, next) { res.json({
})
});
router.get(“/detail”,(req,res,next)=>{
})
module.exports = router;
<a name="7b79f329"></a>#### 使用redis```javascript//安装redis connect-redis模块//cnpm i redis connect-redis -S//redis的配置REDIS_CONF={port:6379,host:"127.0.0.1"}//创建redis客户端const redis = require("redis")const { REDIS_CONF } = require("../config/db")//创建客户端const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)//监听redis客户端是否产生异常redisClient.on("error", err => {console.log(err)})module.exports=redisClient//将redis与session进行关联const session =require("express-session")const RedisStore=require("connect-redis")(session)const redisClient=require("./db/redis")const sessionStore=new RedisStore({client:redisClient})app.use(session({secret:"qwe",cookie:{path:"/",//任意路径都能访问httpOnly:true,//是否允许修改maxAge:24*60*60*1000//过期时间},store:sessionStore}))
日志
- 使用模块
morgan完成日志的输出 ```javascript //morgan的简介https://github.com/expressjs/morgan const logger = require(‘morgan’); / 环境类型 “scripts”: { “start”: “node ./bin/www”, “dev”: “cross-env NODE_ENV=dev nodemon ./bin/www.js”, “prd”: “cross-env NODE_ENV=production nodemon ./bin/www.js” } /
const ENV=process.env.NODE_ENV//获取环境类型 if(ENV!==”production”){ //开发环境/测试环境 app.use(logger(‘dev’)); } else{ //线上环境 const logFilename=path.join(__dirname,”logs”,”access.log”)//拼接文件路径 const writeStream=fs.createWriteStream(logFilename,{ flags:”a” })//创建一个文件日志写入流 app.use(logger(“combined”,{ stream:writeStream//将日志写文件 })) }
<a name="1b2326dc"></a>#### express实现原理```javascriptconst http=require("http");const slice=Array.prototype.slice;class LikeExpress{constructor(){//存放中间件的列表this.router={all:[],//存放使用use注册的中间件get:[],//存放使用get注册的中间件post:[]//存放使用post注册的中间件}}register(path){const info={}if(typeof path==="string"){info.path=path;//从第二个函数开始,转换为数组,存入stack中info.stack=slice.call(arguments,1) //数组//arguments是类数组对象,有一些数组中的方法它们是没有的}else{info.path="/"//从第二个函数开始,转换为数组,存入stack中info.stack=slice.call(arguments,0) //数组}return info;}use(){const info=this.register.apply(this,arguments)this.router.all.push(info)}get(){const info=this.register.apply(this,arguments)this.router.get.push(info)}post(){const info=this.register.apply(this,arguments)this.router.post.push(info)}match(method,url){let stack=[]if(url==='/favicon.ico'){return stack;}//获取routeslet curRoutes=[]curRoutes=curRoutes.concat(this.router.all)curRoutes=curRoutes.concat(this.router[method])curRoutes.forEach(item=>{if(url.indexOf(item.path)===0){stack=stack.concat(item.stack)}})return stack;}//核心的next机制handle(req,res,stack){const next=()=>{//第一个匹配的中间件const middleware=stack.shift()if(middleware){//执行中间件函数middleware(req,res,next)}}next()}callback(){return (req,res)=>{res.json=(data)=>{res.setHeader("Content-type","application/json")res.end(JSON.stringify(data))}const url=req.urlconst method=req.method.toLowerCase()const resultList=this.match(method,url)this.handle(req,res,resultList)}}listen(...args){const server=http.createServer(this.callback())server.listen(...args)}}//工厂函数module.exports=()=>{return new LikeExpress();}//流程前端发送请求->listen->callback->match->handle
koa2框架
- express中间件是异步回调,koa2原生支持
async/await - 简介
安装
koa2的脚手架 npm i koa-generator -g初始化环境 Koa2 koa2-test(文件架名字)启动 npm i & npm run dev
中间件
const Koa = require('koa')const app = new Koa()//出路json格式数据const json = require('koa-json')//错误处理const onerror = require('koa-onerror')//处理表单提交的数据const bodyparser = require('koa-bodyparser')// 日志美化const logger = require('koa-logger')//引入路由const blog=require("./routes/blog")// error handleronerror(app)// 处理表单提交app.use(bodyparser({enableTypes:['json', 'form', 'text']}))//处理json格式数据app.use(json())//处理日志app.use(logger())// 日志处理app.use(async (ctx, next) => {const start = new Date()await next()const ms = new Date() - startconsole.log(`${ctx.method} ${ctx.url} - ${ms}ms`)})// 路由注册app.use(blog.routes(), blog.allowedMethods())// 错误处理app.on('error', (err, ctx) => {console.error('server error', err, ctx)});module.exports = app
- 路由 ```javascript const router = require(‘koa-router’)()
router.prefix(“/api/blog”);//设置请求路径的前缀
router.get(‘/list’, function (ctx, next) { const query = ctx.query;//相等于req.query返回查询字符串 ctx.body = {//相当于 error: 0, query, data: [“获取博客列表”] } })
module.exports = router
<a name="75106630"></a>#### koa中的session-基于koa-generic-session和koa-redis```javascript//安装插件 cnpm i koa-generic-session koa-redis redis -S//处理sessionconst session =require("koa-generic-session")//处理redis,这个模块依赖redisconst redisStore=require("koa-redis")// 设置签名的密钥app.keys=["123"]//设置session,并将session与redis关联app.use(session({cookie:{path:"/",//所有的路由都能使用httpOnly:true,//不允许前端修改maxAge:24*60*60*1000//有效时间},store:redisStore({all:'127.0.0.1:6379'})//配置redis}))
日志
//安装兼容模块(morgan是express中的模块)cnpm i koa-morgan -S/*环境类型"scripts": {"start": "node ./bin/www","dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js","prd": "cross-env NODE_ENV=production nodemon ./bin/www.js"}*/const path=require("path")const fs=require("fs")const morgan=require("koa-morgan")const ENV=process.env.NODE_ENVif(ENV!=="production"){//开发环境app.use(morgan('dev'));}else{//线上环境const logFilename=path.join(__dirname,"logs","access.log")const writeStream=fs.createWriteStream(logFilename,{flags:"a"})app.use(morgan("combined",{stream:writeStream}))}
koa2实现原理
const http=require("http")//组合中间件function compose(middlewareList){return function(ctx){//中间的调用function dispatch(i){const fn=middlewareList[i]try{return Promise.resolve(fn(ctx,dispatch.bind(null,i+1)))}catch(err){return Promise.reject(err)}}return dispatch(0)}}class LikeKoa2{constructor(){this.middlewareList=[]}use(fn){this.middlewareList.push(fn)return this}createContext(req,res){const ctx={req,res}return Object.assign(ctx,req,res)}handleRequest(ctx,fn){return fn(ctx)}callback(){const fn=compose(this.middlewareList)return (req,res)=>{const ctx=this.createContext(req,res)return this.handleRequest(ctx,fn)}}listen(...args){const server=http.createServer(this.callback())server.listen(...args)}}module.exports=LikeKoa2
