1. 渲染静态页面
const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
http.createServer((request,response)=>{
// 将请求的路由取出来 不携带参数
let requestUrl = url.parse(request.url).pathname;
// 如果是小图标 直接返回
if (requestUrl == '/favicon.ico'){
return false;
}
// 获取本次请求文件的后缀名 来确定请求的类型
let extname = path.extname(requestUrl);
// 使用后缀名 确定响应类型
let mime = getMime(extname);
fs.readFile('./xiaou' + requestUrl,(error,data)=>{
if (error){
console.log(error);
}else{
response.writeHead(200,{
'Content-type':mime});
response.end(data);
}
})
}).listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行......');
})
function getMime(name){
switch (name){
case '.html':
return 'text/html';
case '.css':
return 'text/css';
default:
return 'text/plain';
}
}
2. get请求
let query = url.parse(request.url).query;
// querystring模块中有一个parse方法 他能将get参数转化为对象格式
let userObj = qs.parse(query);
// 想userObj中追加属性 追加黑名单
userObj.blacklist = 1;
// 将原有数据读取出来 并将其转化为数组
let userArr = JSON.parse(readPageFile('./data/user.json',200,response));
// 给添加的数据追加ID
userObj.id = userArr[userArr.length - 1].id + 1;
// 向数组中追加数据
userArr.push(userObj);
// 将数组写入到JSON中 覆盖写
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
fs.writeFile('./data/user.json',JSON.stringify(userArr),{
encoding:'utf-8',flag:'w'},err=>{
err ? console.log(err) : response.end('注册成功');
})
3. post请求
// 定义一个空数组 准备装取post数据
let arr = [];
// post方式提交 使用事件驱动 两个事件 一个是data事件 一个是end事件
// 使用request对象触发data事件 第一个参数是事件名data
// 第二个参数是回调函数 回调内置一个参数 参数是传输的数据 post数据
request.on('data',(chunk)=>{
arr.push(chunk);
})
// 使用end事件结束post传参
request.on('end',()=>{
// 获取post数据
let query = Buffer.concat(arr).toString();
// querystring模块中有一个parse方法 他能将get参数转化为对象格式
let userObj = qs.parse(query);
// 将所有的用户取出来 并转化为数组
let userArr = JSON.parse(readPageFile('./data/user.json',200,response));
// 匹配登录 使用find方法进行查找数据是否存在
// userObj.username : 登录者的用户名
// element.username : 所有已注册的用户名
let result = userArr.find(element=>element.username == userObj.username);
// 判断
if (result == undefined){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('用户名不存在 请先去注册');location.href='http://127.0.0.1:3000/register'</script>")
}else{
if (result.blacklist == 0){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('用户已遭多人投诉 你懂');location.href='http://127.0.0.1:3000/login'</script>")
}else{
if (result.password != userObj.password){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('密码错误');location.href='http://127.0.0.1:3000/login'</script>")
}else{
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('登录成功');location.href='http://127.0.0.1:3000/index'</script>")
}
}
}
})
整体案例
const http = require('http');
const fs = require('fs');
const url = require('url');
const path = require('path');
const qs = require('querystring');
http.createServer((request,response)=>{
let requestUrl = url.parse(request.url).pathname;
if (requestUrl == '/favicon.ico'){
return false;
}
if (requestUrl == '/'){
requestUrl = '/index';
}
if (requestUrl == '/index'){
response.end(readPageFile('./view/home.html',200,response));
}else if (requestUrl == '/login'){
response.end(readPageFile('./view/dl.html',200,response));
}else if (requestUrl == '/register'){
response.end(readPageFile('./view/zc.html',200,response));
}else if (requestUrl == '/insert'){
let query = url.parse(request.url).query;
// querystring模块中有一个parse方法 他能将get参数转化为对象格式
let userObj = qs.parse(query);
// 想userObj中追加属性 追加黑名单
userObj.blacklist = 1;
// 将原有数据读取出来 并将其转化为数组
let userArr = JSON.parse(readPageFile('./data/user.json',200,response));
// 给添加的数据追加ID
userObj.id = userArr[userArr.length - 1].id + 1;
// 向数组中追加数据
userArr.push(userObj);
// 将数组写入到JSON中 覆盖写
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
fs.writeFile('./data/user.json',JSON.stringify(userArr),{
encoding:'utf-8',flag:'w'},err=>{
err ? console.log(err) : response.end("<script>alert('注册成功');location.href='http://127.0.0.1:3000/login'</script>");
})
}else if (requestUrl == '/loginto'){
// 定义一个空数组 准备装取post数据
let arr = [];
// post方式提交 使用事件驱动 两个事件 一个是data事件 一个是end事件
// 使用request对象触发data事件 第一个参数是事件名data
// 第二个参数是回调函数 回调内置一个参数 参数是传输的数据 post数据
request.on('data',(chunk)=>{
arr.push(chunk);
})
// 使用end事件结束post传参
request.on('end',()=>{
// 获取post数据
let query = Buffer.concat(arr).toString();
// querystring模块中有一个parse方法 他能将get参数转化为对象格式
let userObj = qs.parse(query);
// 将所有的用户取出来 并转化为数组
let userArr = JSON.parse(readPageFile('./data/user.json',200,response));
// 匹配登录 使用find方法进行查找数据是否存在
// userObj.username : 登录者的用户名
// element.username : 所有已注册的用户名
let result = userArr.find(element=>element.username == userObj.username);
// 判断
if (result == undefined){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('用户名不存在 请先去注册');location.href='http://127.0.0.1:3000/register'</script>")
}else{
if (result.blacklist == 0){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('用户已遭多人投诉 你懂');location.href='http://127.0.0.1:3000/login'</script>")
}else{
if (result.password != userObj.password){
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('密码错误');location.href='http://127.0.0.1:3000/login'</script>")
}else{
response.writeHead(200,{
'Content-type':'text/html;charset=utf-8'});
response.end("<script>alert('登录成功');location.href='http://127.0.0.1:3000/index'</script>")
}
}
}
})
}else{
response.end(readPageFile('./view/404.html',404,response));
}
}).listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行......');
})
// 读取页面的函数
function readPageFile(pageUrl,status = 0,response = {
}){
response.writeHead(status,{
'Content-type':'text/html'});
return fs.readFileSync(path.resolve(__dirname,pageUrl),'utf-8');
}
4. express框架
简介
Express 是一个简洁而灵活的 Node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用
如果不计中间件,主体框架只有一千余行代码,非常简练
Express 不对 Node.js 已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的功能
Express内部还是使用的http模块实现服务器创建和监听, 对http模块进行了二次封装
express自身内部只是扩展了路由和中间件
使用
下载express模块, 命令 npm install express
在.js文件中, 引入express模块 初始化服务器对象
设置路由接口地址 (以供浏览器访问) 监听端口号 (给服务器设置端口号)
5. 路由
路由组成
URL目录部分太长了, 可以让后台规定路由的路径(/api/getNew), 然后当访问时, 让后台去转发寻找
例如: 访问 /image/rB.jpg 就相当于 访问的是上面的路径资源 (但是具体访问什么, 还是后台说了算)
不同的路径, 对应的不同路由 (路由 = 路径)
所以所有的请求, 都看后台如何处理
API接口 = 路由 = 路径 = url地址
路由动态
get路由 : 只能通过get方式进行访问
post路由 : 只能通过post方式进行访问
all路由 : 可以使用任何方式进行访问
use路由 : 可以使用任何方式进行访问
const express = require('express');
// console.log(express);
// 实例化一个应用 使用这个应用
const app = express();
// console.log(app);
// 使用express创建一个路由 get方法
app.get('/index',(request,response)=>{
// 在express中 我们响应数据使用send方法 注意 send和end一样 只能响应字符串
response.send('第一个程序');
});
// 使用post方法创建一个路由
app.post('/ppp',(request,response)=>{
response.send('第二个程序 这是post');
})
// 使用all方法 接受所有的方式
app.all('/all',(request,response)=>{
response.send('这是第三程序 可以接受任何');
})
// 使用use中间件 接受任何方式
// app.use('/uuu',(request,response)=>{
// response.send('这是use方法');
// })
app.use((request,response)=>{
response.send('404');
})
// 监听
app.listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行......');
})
路径正则
? 匹配0个或者1个字符 ?前边的
+ 匹配1个或多个+号前边的字符
* 通配符 匹配0个或者多个 *所在的位置
() 将里边的字符算作一个整体
正则匹配路由
const express = require('express');
const app = express();
// 定义路由
// 正则表达式匹配路由
// ? : 零次或一次匹配其前字符
// app.get('/ab?cd',(request,response)=>{
// response.send('匹配成功');
// })
// + : 一次或多次匹配其前字符 至少一次
// app.get('/ab+cd',(request,response)=>{
// response.send('匹配成功');
// })
// () : 将括号中当成一个整体
// app.get('/a(bc)?d',(request,response)=>{
// response.send('匹配成功');
// })
// * : 零次、一次或多次匹配*所在位置
// app.get('/ab*cd',(request,response)=>{
// response.send('匹配成功');
// })
// 正则表达式匹配
app.get(/a/,(request,response)=>{
response.send('匹配成功');
})
app.listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行');
})
路径参数解析
携带参数的路由 参数以:分开
路径参数是命名的url字段 用于捕获在url中的位置
捕获的值放在req.params中 路径的:user_id user_id对象的键
const express = require('express');
const app = express();
// 定义路由
/*
在使用路由传递参数的时候 和get参数差不多
都是通过地址栏进行传递参数 但是还是有些不同的 至于不同点
在路由传参中 我们在浏览器端 不需要在使用?进行传递参数 只需要直接传递就可以了
在我们后端接受参数的时候 不需要使用url或者query等方法
我们直接使用:参数名就可以了
直接定义在路由中
在后台接受到参数的时候 我们的参数存储在request对象中的params属性中
他是一个属性 也是一个对象 对象中的数据就是路由参数
是键值对的形式存在的 如果说没有传参 没有参数 那么默认值是空对象
*/
app.get('/index/:name/:age',(request,response)=>{
let {
name,age} = request.params;
console.log(request.params);
console.log(name,age);
response.send('你好 兔头');
})
app.listen(3000);
路由级别路由
也就是我们说的二级路由
一个网站中至少有几十个路由 不能都写在一个页面 那样读取困难 优化不好
所以说 我们每一个模块的路由都是分开写的 分别写在不同的路由模块中
定义路由模块 我们需要使用到express中的Router对象
6. 中间件
什么是中间件
Express是一个自身功能极简,完全是路由和中间件构成一个web开发框架
一个Express应用就是在调用各种中间件。中间件在Express开发中很重要
中间件函数能够访问请求对象 (req)、响应对象 (res) 以及应用程序的请求/响应循环中的下一个中间件函数
该next功能是中间件函数中的一个功能,当被调用时,它将执行当前中间件之后的中间件
下一个中间件函数通常由名为 next 的变量来表示
内置中间件
内置中间件我们只使用一个 使用static
static : 渲染静态资源的中间件
urlencode : 使用第三方中间件完成功能 接受表单数据
json : 使用第三方中间件完成功能 接受JSON数据
const express = require('express');
const path = require('path');
const app = express();
// 使用static渲染进行资源
// 使用use中间件进行渲染
// 内置一个或者两个参数
// 第一个参数是路由 可选
// 第二个参数是express.static方法 方法内置一个参数 参数是渲染的资源路径
// 主要的作用是渲染CSS JS IMAGE等静态资源
// app.use(express.static('../xiaou/'));
app.use('/xiaou',express.static(path.resolve(__dirname,'../xiaou/')));
app.listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行......');
})
错误处理中间件
status : 处理http响应码
send : 处理404
自定义中间件
自定义中间件是自己定义的中间件 使用同名路由
路由中没有响应 需要使用next调用下一个中间件
最后一个路由将其直接响应出去
const express = require('express');
const app = express();
// 自定义中间件中 回调函数中可以传递第三个参数
// 在自定义中间键中 有若干个路由 但是都是一个名字 不能有响应
// 但是可以有next 使用next方法调用下一个同名中间件
app.use('/index',(request,response,next)=>{
let hotSearch = [
{
name : '口红'},
{
name : '面膜'},
{
name : '项链'},
{
name : '箱包'},
{
name : '高跟鞋'},
{
name : '防晒霜'},
{
name : '耳钉'},
{
name : '搓衣板'}
];
request.hotSearch = hotSearch;
next();
})
app.use('/index',(request,response,next)=>{
let first = [
{
name : '导弹'},
{
name : '原子弹'},
{
name : '氢弹'},
{
name : '达姆弹'},
{
name : '荷包蛋'},
{
name : '茶叶蛋'},
{
name : '混蛋'},
{
name : '滚蛋'}
];
request.first = first;
next();
})
app.use('/index',(request,response)=>{
let footer = [
{
name : '优就业'},
{
name : '中公教育'},
{
name : '腾讯'},
{
name : '网易'},
{
name : '饿了吗'},
{
name : '美团'},
{
name : '赶集网'},
{
name : '智联'}
];
let arr = [request.hotSearch,request.first,footer];
response.send(arr);
})
app.listen(3000,'127.0.0.1',()=>{
console.log('服务器正在运行......');
})
第三方中间件
第三方中间件使用的其实就是第三方模块
依赖于express的第三方模块就是express的中间件
常用的第三方中间件有
body-parser
cookie-parser
express-session
multer
crypto
ejs
pug
nodemon