EXPRESS
nodejs库,不用基础做起,工作简单化,点击进入官网,类似的还有 koa
特点
二次封装,非侵入式,增强形
搭建web服务
let express=require('express')
let server=express()
let server.listen(端口,地址,回调)
静态资源托管
server.use(express.static('./www'));
接口响应
支持各种请求姿势:get、post、put、delete…
server.请求姿势API(接口名称,处理函数)
server.get(url,(req,res,next)=>{})
server.post(url,(req,res,next)=>{})
...
req 请求体
request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性
req.query //获取地址栏的数据
req.body //获取非地址栏的数据 依赖中间件
req.params //获取动态接口名
req.method //获取前端提交方式
req.body依赖中间件
中间件使用:body-parser
- npm install body-parser
- let bodyParser = require(‘body-parser’)
- app.use(bodyParser ())
res 响应体
response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据
res.send(any) //对等 res.write + end
res.end(string|buffer)
res.json(json) //返回json
res.status(404).send({error:1,msg:"Sorry can't find that!"}) //返回一个404
res.jsonp(响应数据) //调用请求时的回调函数并传递响应数据
res.sendFile(path.resolve('public/error.html'))//渲染纯 HTML 文件
//引入 express框架
const express = require("express")
//引入中间件
const bodyParser=require("body-parser")
//创建 web服务器
const app = express()
const path=require("path")
//监听端口
app.listen(3000,"localhost",()=>{
console.log("监听端口3000")
})
//资源托管
// express.static("")
app.use(express.static("./www"))
app.use(bodyParser())
//处理接口响应
// app.get("/api/goods",(req,res)=>{
// console.log("godds接口",req.query)
// res.end()
// })
// //处理接口响应
// app.get("/api/goods",(req,res)=>{
// console
// })
//post
// app.post("/api/goods",(req,res)=>{
// console.log("goods接口",req.method,req.query)
// res.end()
// })
//动态接口
//根据id进行处理
// app.get("/api/goods/:id",(req,res)=>{
// console.log("详情...",req.params.id)
// res.end()
// }
// )
//send
// app.get("/api/goods/:id",(req,res)=>{
// console.log("详情...",req.params.id)
// res.send('123')//返回数据 res.write()+res.end()
//
// }
// )
//返回json数据
// app.get("/api/goods/:id",(req,res)=>{
// console.log("详情...",req.params.id)
// res.json({a:123,b:456})
// res.end()
// }
// )
//status
// app.get("/api/goods/:id",(req,res)=>{
// console.log("详情...",req.params.id)
// res.status(404).send({error:404,msg:"Can't find that!"})
// res.end()
// }
// )
app.get("/api/home",(req,res)=>{
console.log("jsonp传递来的数据",req.query)
res.jsonp({err:0,data:{a:1,b:2}})
}
)
// app.get("/api/login",(req,res)=>{
// console.log("jsonp传递来的数据",req.query,req.body)
// res.send({data:{a:1,b:2}})
//
// }
// )
//path
// app.get("/api/home",(req,res)=>{
// res.sendFile(path.resolve('www/index.html'))
// })
jsonp响应
server.set('jsonp callback name','cb')//默认callback
server.get('/jsonp接口',(req,res,next)=>res.jsonp(数据))
实例:
//1.引入express框架 (url/querystring/path/fs/http等)
const express = require("express")
//1.引入body-parser中间件
const bodyParser = require("body-parser")
const path = require("path")
//2.创建web服务器
const app = express()
//3.监听端口
app.listen(3000,"localhost",()=>{
console.log("端口3000正在监听着哦....")
})
//4.资源托管 (http://localhost:3000的时候,内部会自动的找到静态资源www目录下的index.html)
app.use(express.static("./public"))
//2.通过app.use使用bodyParser中间件
app.use(bodyParser())
//接口响应
// app.get("/api/home",(req,res)=>{
// console.log("返回一个静态页面...")
// res.sendFile(path.resolve('public/index.html'))//渲染纯 HTML 文件
// })
//响应jsonp数据
//res.jsonp(响应数据) //调用请求时的回调函数并传递响应数据
//客户端发起jsonp请求,创建一个script标签,内部需要创建一个全局函数
app.get("/api/home",(req,res)=>{
console.log("jsonp来的数据",req.query)
res.jsonp({err:0,data:{a:1,b:2}}) //返回一个结果,调用客户端传递来的callback=jsonp_XXXXX方法调用执行,传递参数给他
})
//ajax响应
// app.get("/api/login",(req,res)=>{
// console.log("ajax请求的响应",req.query,req.body)
// res.send({err:0,data:{msg:"ajax请求...."}})
// })
前端页面:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="author" content="" />
<meta name="copyright" content="" />
<title></title>
<link href="css/index.css" rel="stylesheet" />
<script src="./js/jsonp.js"></script>
<script src="./js/ajax.js"></script>
</head>
<script>
//jsonp
window.onload=function(){
jsonp({
url:"http://localhost:3000/api/home",
data:{start:10,end:20},
success:(data)=>{
console.log("获取服务端传递来的数据data:",data)
}
})
}
//ajax
// window.οnlοad=function(){
// ajax({
// url:"http://localhost:3000/api/login",
// data:{a:10,b:20},
// success:data=>{
// console.log("ajax请求数据:",data)
// }
// })
// }
</script>
<body>
</body>
</html>
jsonp.js:
//options url,data,timeout,success,error
function jsonp(options){
options = options || {};
if(!options.url){
return;
}
options.data = options.data || {};
options.cbName = options.cbName || "cb";
options.timeout = options.timeout || 0;
var fnName = "jsonp_"+ Math.random();
fnName = fnName.replace("." ,"");
options.data[options.cbName] = fnName;
var arr = [];
for(var i in options.data){
arr.push(i + "=" + encodeURIComponent(options.data[i]));
}
var str = arr.join("&");
window[fnName] = function (json){
options.success && options.success(json);
clearTimeout(timer);
oHead.removeChild(oS);
window[fnName] = null;
}
var oS = document.createElement("script");
oS.src = options.url + "?" + str;
var oHead = document.getElementsByTagName("head")[0];
oHead.appendChild(oS);
if(options.timeout){
var timer = setTimeout(function(){
options.error && options.error();
//window[fnName] = null;
window[fnName] = function(){};
},options.timeout);
}
}
ajax.js:
//url,data,type,timeout,success,error
function ajax(options){
//-1 整理options
options=options||{};
options.data=options.data||{};
options.timeout=options.timeout||0;
options.type=options.type||'get';
//0 整理data
var arr=[];
for(var key in options.data){
arr.push(key+'='+encodeURIComponent(options.data[key]));
}
var str=arr.join('&');
//1 创建ajax对象
if(window.XMLHttpRequest){
var oAjax=new XMLHttpRequest();//[object XMLHttpRequest]
}else{
var oAjax=new ActiveXObject('Microsoft.XMLHTTP')
}
if(options.type=='get'){
//2.
oAjax.open('get',options.url+'?'+str,true);
//3.
oAjax.send();
}else{
//2.
oAjax.open('post',options.url,true);
//设置请求头
oAjax.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
oAjax.send(str);//身子
}
//3.5 超时
if(options.timeout){
var timer=setTimeout(function(){
alert('超时了');
oAjax.abort();//中断ajax请求
},options.timeout);
}
//4.
oAjax.onreadystatechange=function(){//当准备状态改变时
if(oAjax.readyState==4){//成功失败都会有4
clearTimeout(timer);
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
options.success && options.success(oAjax.responseText);
}else{
options.error && options.error(oAjax.status);//http 0
}
}
};
};
处理一部分接口
共有业务逻辑,在一起给处理了
server.all('/admin/*',(req,res,next)=>{}))
all匹配全路径 处理所有HTTP
需要next 延续后续
实例:
//1.引入express框架 (url/querystring/path/fs/http等)
const express = require("express")
//1.引入body-parser中间件
// const bodyParser = require("body-parser")
const path = require("path")
//2.创建web服务器
const app = express()
//3.监听端口
app.listen(3000,"localhost",()=>{
console.log("端口3000正在监听着哦....")
})
//4.资源托管 (http://localhost:3000的时候,内部会自动的找到静态资源www目录下的index.html)
app.use(express.static("./public"))
//2.通过app.use使用bodyParser中间件
// app.use(bodyParser())
app.get("/api/*",(req,res,next)=>{
console.log("a,b的所有的公共的业务逻辑...")
next() //使得后续得以运行
})
app.get("/api/a/*",(req,res,next)=>{
console.log("/api/a的数据请求....")
next()
})
app.get("/api/a/aa",(req,res)=>{
console.log("/api/a/aa的数据请求....")
})
app.get("/api/b",(req,res)=>{
console.log("/api/b的数据请求....")
})
use
安装中间件、路由、接受一个函数,
server.use([地址],中间件|路由|函数体)
实例:
//1.引入express框架 (url/querystring/path/fs/http等)
const express = require("express")
//1.引入body-parser中间件
// const bodyParser = require("body-parser")
const path = require("path")
//2.创建web服务器
const app = express()
//3.监听端口
app.listen(3000,"localhost",()=>{
console.log("端口3000正在监听着哦....")
})
//4.资源托管 (http://localhost:3000的时候,内部会自动的找到静态资源www目录下的index.html)
app.use(express.static("./public"))
//2.通过app.use使用bodyParser中间件
// app.use(bodyParser())
//app.use方法
//app.use([地址])
//默认use不写地址就是截获了根路径 app.use("/",callback)
// app.use((req,res,next)=>{
// console.log("进入app.use了哦...")
// next() //向下延续
// })
// app.use("/api/*",(req,res,next)=>{ //app.all("/api/*",callback)
// console.log("进入app.use了哦...")
// next() //向下延续
// })
//next管道函数
// app.use((req,res,next)=>{
// console.log("这是app.use.....")
// req.query = "abcdefg"
// next()
// })
// app.get("/api/home",(req,res,next)=>{
// console.log("进入了/api/home....",req.query)
// })
中间件
middleware, 处理自定义业务,只处理请求到结束响应的中间部分
举例
npm i body-parser -S //安装包
let bodyParser=require('body-parser')//引入中间件
server.use(bodyParser())//安装中间件
body-parser 使用方式,实时查询 npm,可获得最新
实例:
//引入express
let express = require("express")
//1.引入中间件body-parser
let bodyParser = require("body-parser") //中间件可以是一个函数体
//搭建服务器
let app = express()
//2.让app使用中间件 (希望增强某种功能的时候,可以引入一些中间件)
// app.use(bodyParser())
// app.use(bodyParser({
// limit:10
// }))
// app.use(bodyParser.urlencoded({
// limit:102400
// }))
//监听一下端口
app.listen(3000)
// app.use((req,res,next)=>{
// console.log("进入app.use....")
// req.abc = "hello world"
// next()
// })
app.get("/api/home",(req,res)=>{
console.log("/api/home",req.body)
})
自己封装bodyParser
//自己封装bodyParser
//引入querystring模块
//1.
// let querystring = require("querystring")
// let bodyParser=()=>{
// console.log("中间件")
// return (req,res,next)=>{
// let str=""
// req.on("data",chunk=>str+=chunk)
// req.on("end",()=>{
// req.body=querystring.parse(str)
// next()
// })
// }
// }
// module.exports =bodyParser
//2.
// let querystring=require("querystring")
// let bodyParser=(options)=>{
// options = options || {}
// options.limit = options.limit || 102400
// return (req,res,next)=>{
// let str=""
// req.on("data",chunk=>str+=chunk)
// req.on("end",()=>{
// if(str.length>options.limit){
// throw new Error()
// }
// else{
// req.body=querystring.parse(str)
// }
// next()
// })
// }
// }
//3.
let querystring=require("querystring")
module.exports ={
urlencoded:(options)=>{
return(options)=>{
options = options || {}
options.limit = options.limit || 102400
return (req,res,next)=>{
let str=""
req.on("data",chunk=>str+=chunk)
req.on("end",()=>{
if(str.length>options.limit){
throw new Error()
}
else{
req.body=querystring.parse(str)
}
next()
})
}
}
}
}
引入封装模块:
let express=require("express")
// let bodyParser=require("body-parser")
//引入封装好的模块 路径名一定要正确(当前bdParser.js在./middleware/下)
let bodyParser=require("./middleware/bdParser2")
let app = express()
//监听端口
app.listen(3000,"localhost",()=>{
console.log("监听端口3000")
})
// app.use(bodyParser())
// app.use(bodyParser({
// // limit:10
// }))
app.use(bodyParser.urlencoded({
limit:1024
}))
// app.use(express.static("./www"))
app.post("/api/old",(req,res,next)=>{
console.log(req.body)
res.end()
})
后端跳转
res.redirect(url) 指向一个接口
实例:
let express= require("express")
let bodyParser= require("body-parser")
let app=express()
app.listen(3000)
app.use(bodyParser())
//老的接口
//redirect重定向
// let body;
// app.post("/api/old",(req,res,next)=>{
// body=req.body
// res.redirect("http://localhost:3000/api/new")
// })
// app.post("/api/new",(req,res,next)=>{
// console.log("old->new",body)
// res.end()
// })
//redirect只能用在get上
let query
app.get("/api/old",(req,res,next)=>{
query=req.query
res.redirect("http://localhost:3000/api/new")//后端跳转
})
app.get("/api/new",(req,res,next)=>{
console.log("old->new",query)
res.end()
})
扩展
req
- req.app:当callback为外部文件时,用req.app访问express的实例
- req.baseUrl:获取路由当前安装的URL路径
- req.cookies:Cookies
- req.fresh / req.stale:判断请求是否还「新鲜」
- req.hostname / req.ip:获取主机名和IP地址
- req.originalUrl:获取原始请求URL
- req.path:获取请求路径
- req.protocol:获取协议类型
- req.route:获取当前匹配的路由
- req.subdomains:获取子域名
- req.accepts():检查可接受的请求的文档类型
- req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
- req.get():获取指定的HTTP请求头
- req.is():判断请求头Content-Type的MIME类型
res
- res.app:同req.app一样
- res.append():追加指定HTTP头
- res.set()在res.append()后将重置之前设置的头
- res.cookie(name,value [,option]):设置Cookie
- opition: domain / expires / httpOnly / maxAge / path / secure / signed
- res.clearCookie():清除Cookie
- res.download():传送指定路径的文件
- res.get():返回指定的HTTP头
- res.location():只设置响应的Location HTTP头,不设置状态码或者close response
- res.render(view,[locals],callback):渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
- res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
- res.set():设置HTTP头,传入object可以一次设置多个头
- res.status():设置HTTP状态码
- res.type():设置Content-Type的MIME类型
身份验证
HTTP 是一种没有状态的协议,也就是它并不知道是谁访问。客户端用户名密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证
session
思想
1、客户端用户名跟密码请求登录
2、服务端收到请求,去库验证用户名与密码
3、验证成功后,服务端种一个cookie或发一个字符到客户端,同时服务器保留一份session
4、客户端收到 响应 以后可以把收到的字符存到cookie
5、客户端每次向服务端请求资源的cookie会自动携带
6、服务端收到请求,然后去验证cookie和session,如果验证成功,就向客户端返回请求的库数据
Session存储位置: 服务器内存,磁盘,或者数据库里
Session存储内容: id,存储时间,用户名等说明一下登录的用户是谁
客户端携带 : cookie自动带,localStorage手动带
如何保存信息给浏览器
前端种:
cookie/localstorage
后端种:
服务器给浏览器种cookie: cookie-parser
服务器给浏览器种cookie的同时在服务器上生成seesion: cookie-session
cookie-session
安装引入
let cookieSession = require('cookie-session')
配置中间件
app.use(cookieSession({
name:'保存到服务器的session的名字',
keys:[必传参数,代表加密层级],
maxAge:1000 //保留cookie的时间
}))
种cookie,备份session
req.session.key=value
读cookie对比session
req.session.key 返回true
删除cokkie、session
delete req.session.key
req.session.key = undefined
验证登录实例:
let express = require("express")
let cookieSession = require("cookie-session")
//搭建服务器
let app = express()
//静态资源托管
app.use(express.static("./public"))
//监听端口
app.listen(3000)
//使用中间件cookieSession
app.use(cookieSession({
name:"mycookie", //后端给前端种cookie的名字叫做mycookie
keys:["aa","bb","cc"], //加密层级
maxAge:1000*30 //cookie的失效时间
}))
//验证用户身份
app.get("/api/login",(req,res)=>{
//1)校验客户端传递来的用户名与密码和数据库里面的是否一致
//2)给客户端种cookie,并且同时服务端留一份session
req.session.nz1906 = "userId"
//3)后端种完cookie后,就可以给前端返回数据
res.send({
err:0,
msg:"恭喜您,登录成功了!",
data:{
username:"张三"
}
})
})
//自动登录功能
app.get("/api/user",(req,res)=>{
//读cookie对比session
//如果前端传递来的cookie是有效的,那么req.session.nz1906的值就是“userId"
//如果前端传递来的cookie失效了,那么req.session.nz1906的值就是undefined
let pass = req.session.nz1906 //如果用户登录了,那么pass="userId",如果用户cookie失效或者没有,那么返回null
if(pass){
//说明用户身份一直存在的,取库数据,并且返回
res.send({
erro:0,
data:"/api/user的数据!!!"
})
}else{
res.send({
err:1,
data:"用户未登录...或者登录过期了.."
})
}
res.end()
})
//注销登录
app.get("/api/logout",(req,res)=>{
//删除服务端session和客户端的cookie
req.session.nz1906 = undefined
res.end()
})