文章目录

  • 1.概念
  • 2.创建web服务器
  • 3.获取报文
  • 4.响应报文
  • 5.请求参数
    • GET请求参数
    • POST请求参数
  • 6.路由
  • 7.静态资源和动态资源
  • 8.同步API和异步API
    • 同步API
    • 异步API
    • 区别
    • 回调函数
      • 回调地狱
      • 回调地狱的解决(Promise)
    • 异步函数
  • 9.Node全局对象global
  • 10.数据库(MongoDB)
    • mongoose第三方包
      • 下载
      • 启动
      • 连接
      • 创建数据库
      • MongoDB的增删改查
        • 创建集合
        • 创建文档(向集合中插入数据)
        • 向MongoDB数据库中导入数据
        • 查询文档
        • 删除文档
        • 更新文档
        • mongoose验证
        • 集合关联
  • 11.模板引擎
    • art-template
    • 语法
      • 标准语法
      • 原始语法
    • 静态资源访问处理
  • 12.Express框架
    • 特点
    • 中间件
      • app.use中间件
      • 中间件的应用
      • 错误处理中间件
    • 捕获错误
    • 构建模块化路由
    • GET、POST参数的获取
      • GET参数的获取
      • POST参数的获取
    • Express路由参数
    • 静态资源的处理
    • 模板引擎
    • app.locals对象

1.概念

  1. URL(统一资源定位符)
    URL的组成:传输协议://服务器IP或域名:端口/资源所在位置标识
  2. 开发过程中客户端和服务器端说明
    • 开发阶段,客户端和服务器端使用同一台电脑(客户端:浏览器;服务器端:Node) 连接:本地服务器,域名:localhost ;IP:127.0.0.1
    • 客户端:在浏览器中运行的部分,就是用户看到并与之交互的界面程序,使用HTML、css、JavaScript构建
    • 服务器端:在服务器中运行的部分,负责存储数据和处理应用逻辑

2.创建web服务器

3.获取报文


4.响应报文



5.请求参数

GET请求参数

参数被放置在浏览器地址栏中:http://localhost:3000<font color="red">?name=falcon&age=20</font>
// 引入url,用于处理url地址
const url = require('url')// 获取请求地址
// console.log(req.url);
// 第一个参数:要解析的url地址;第二个参数(true):将查询参数解析成对象形式
// console.log(url.parse(req.url,true).query);
// let params = url.parse(req.url,true).query
// console.log(params.name);
// console.log(params.age);
// 参数解构
let { query,pathname } = url.parse(req.url,true)
console.log(query.name);
console.log(query.age);
if(pathname == '/index' || pathname == '/'){// res.end('<h2>index page</h2>')res.end('<h2>欢迎来到首页</h2>')
}else if(pathname == '/list'){res.end('list page')
}else{res.end('not found')
}

POST请求参数

参数被放置在请求体中进行传输;获取post参数需要用到data事件和end事件;使用querystring模块将参数转换为对象格式
//post.js
// 引入http模块
const http = require('http')
// 创建网站服务器
const app = http.createServer()
// 引入querystring,能把字符串转换为对象格式
const querystring = require('querystring')// 客户端发送请求
app.on('request',(req,res)=>{// post参数是通过事件的方式接受的:data(请求参数传递时) 和 end(请求参数传递完成时)let postParams = '';req.on('data', params => {postParams += params})req.on('end',()=>{// console.log(postParams);postParams = querystring.parse(postParams)console.log(postParams);})res.end('ok')
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
<!-- form.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- method 指定当前表单的提交方式;action 指定当前表单的提交地址 --><form action="http://localhost:3000" method="POST"><input type="text" name="username" id=""><input type="password" name="password" id=""><input type="submit" value="提交"></form>
</body>
</html>

6.路由

//route/app.js
// 引入http模块
const http = require('http')
// 引入url
const url = require('url')
// 创建网站服务器
const app = http.createServer()// 客户端发送请求
app.on('request',(req,res)=>{// 获取客户端请求方式const method = req.method.toLowerCase()// 获取客户端请求地址const pathname = url.parse(req.url).pathname// 对响应报文的处理res.writeHead(200,{'content-type':'text/html;charset=utf8'})if(method == 'get'){if(pathname == '/' || pathname == '/index'){res.end('欢迎来到首页');}else if(pathname == '/list'){res.end('list page')}else{res.end('not found')}}else if(method == 'post'){}// res.end('ok')
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

7.静态资源和动态资源

静态资源:服务器不需要处理,可以直接响应给客户端的资源为静态资源
动态资源:相同的请求地址不同的响应资源

//静态资源实例
// 引入http
const http = require('http')
// 引入url模块,用于处理URL地址
const url = require('url')
// 引入path模块,用于获取文件的绝对路径
const path = require('path')
// 引入fs模块,读取文件
const fs = require('fs')
// 引入mime,能根据当前请求的路径,分析出资源的类型,并将资源类型通过返回值的方式返回
const mime = require('mime')// 创建web服务器
const app = http.createServer()// 客户端发送请求
app.on('request',(req,res) => {// 获取用户的请求路径let pathname = url.parse(req.url).pathnamepathname = pathname == '/' ? '/default.html' : pathname// 将用户的请求路径转换为服务器实际的硬盘路径// res.end(path.join(__dirname,'public' + pathname))let realPath = path.join(__dirname,'public' + pathname)// 获取资源的类型// console.log(mime.getType(realPath));let type = mime.getType(realPath)// 文件读取成功,error为null,result为读取的内容;读取失败,error为失败的信息内容,result为nullfs.readFile(realPath,(error,result) => {// 错误处理if(error != null){res.writeHead(404,{'content-type':'text/html;charset=utf8'})res.end('文件读取失败!')return}// 读取正确res.writeHead(200,{'content-type':type})res.end(result)})
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');

8.同步API和异步API

同步API

只有当前API执行完成后,才能执行下一个API

console.log('before');
setTimeout(function(){console.log('last');
},2000)
console.log('after');

异步API

当前API的执行不会阻塞后续代码的执行

区别

  1. 同步API可以从返回值中拿到API执行结果,异步API不可以
  2. 同步API代码的执行顺序会从上到下依次执行,前面代码会阻塞后面代码的执行;异步API不会等API执行完成后再向下执行代码

回调函数

自己定义函数让别人去调用

回调地狱
// 引入fs模块
const fs = require('fs')// 多层的循环嵌套
fs.readFile('./1.txt','utf8',(err,result1) => {console.log(result1);fs.readFile('./2.txt','utf8',(err,result2) => {console.log(result2);fs.readFile('./3.txt','utf8',(err,result3) => {console.log(result3);})})
})
回调地狱的解决(Promise)

Promise解决Node.js异步编程中回调地狱的问题

// 引入fs模块
const { rejects } = require('assert');
const fs = require('fs');
const { resolve } = require('path');// 解决回调地狱问题
function p1(){return new Promise((resolve,reject) => {fs.readFile('./1.txt','utf8',(err,result1) => {resolve(result1)})})
}function p2(){return new Promise((resolve,reject) => {fs.readFile('./2.txt','utf8',(err,result2) => {resolve(result2)})})
}function p3(){return new Promise((resolve,reject) => {fs.readFile('./3.txt','utf8',(err,result3) => {resolve(result3)})})
}
// 没有嵌套,解决了回调地狱的问题
p1().then((r1) => {console.log(r1);return p2()
})
.then((r2) => {console.log(r2);return p3()
})
.then((r3) => {console.log(r3);
})

异步函数

可以将异步代码写成同步的形式,让代码不再有回调函数的嵌套,使代码变得清晰明了

//异步函数基础语法// 1.在普通函数前面加async,普通函数变异步函数
// 2.异步函数默认返回值是promise对象
// 3.在异步函数内部使用throw关键字进行错误抛出
/*** await关键字* 1.它只能出现在异步函数中* 2.await promise 它可以暂停异步函数的执行,等待promise对象返回结果后再向下执行*/
async function fn(){// throw之后的代码不在执行throw '发生错误';return 123
}
// console.log(fn());
fn().then((data) => {console.log(data);
}).catch((err) => {console.log(err);
})async function p1(){return 'p1'
}
async function p2(){return 'p2'
}
async function p3(){return 'p3'
}
async function run(){let r1 = await p1()let r2 = await p2()let r3 = await p3()console.log(r1);console.log(r2);console.log(r3);
}
run()
// 导入fs模块
const fs = require('fs')
// 引入promisify方法.用来改造现有异步函数的api,让其返回promise对象,从而支持异步函数语法
const promisify = require('util').promisify
// 此时readFile的读取结果就是一个promise对象
const readFile = promisify(fs.readFile) async function run(){let r1 = await readFile('./1.txt','utf8')let r2 = await readFile('./2.txt','utf8')let r3 = await readFile('./3.txt','utf8')console.log(r1);console.log(r2);console.log(r3);
}
run()

9.Node全局对象global

浏览器中全局对象是window,node中全局对象是global

// 与不带global结果相同
globalThis.console.log('global下的log方法')
globalThis.setTimeout(function(){console.log('123');
},2000)

10.数据库(MongoDB)

使用数据库的原因:

MongoDB可视化软件:MongoDB Compass

mongoose第三方包

关于数据库的所有操作都是异步操作

  1. 使用node.js操作MongoDB数据库需要依赖node.js第三方包mongoose
下载

npm install mongoose

启动

命令行工具中停止mongodb:net stop mongoDB;启动mongodb:net start mongoDB

连接

创建数据库

MongoDB中不需要显示创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建

MongoDB的增删改查
创建集合

分为两步,对集合设定规则;创建集合(大写,生成后的数据库是小写形式并加s)

创建文档(向集合中插入数据)

分为两步:创建实例集合;调用实例对象下的save方法将数据保存到数据库中


create方法也返回promise对象

// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{useNewUrlParser: true,useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))// 创建集合规则
const courseSchema = new mongoose.Schema({name:String,author:String,isPublished:Boolean
})
// 使用规则创建集合:两个参数,集合名称,创建集合规则
const Course = mongoose.model('Course',courseSchema) //courses// // 方法一:创建集合构造函数实例
// const course = new Course({//   name:'node.js基础',
//   author:'falcon讲师',
//   isPublished:true
// })
// // 将数据保存到数据库中
// course.save()// // 方法二:创建集合构造函数实例
// Course.create({name:'JavaScript',author:'alice',isPublished:false},(err,result) => {//   console.log(err);
//   console.log(result);
// })// 方法三:创建集合构造函数实例
Course.create({name:'html',author:'lily',isPublished:false})
.then(res => console.log(res))
.catch(err => console.log(err))
向MongoDB数据库中导入数据

准备:找到MongoDB的安装目录,将安装目录下的bin目录放置在环境变量中

mongoimport -d 数据库名 -c 集合名称 --file/--jsonArray 要导入的数据文件

查询文档







删除文档

更新文档


// 引入操作MongoDB的第三方包mongoose
const { countReset } = require('console')
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{useNewUrlParser: true,useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))// 创建集合规则
const userSchema = new mongoose.Schema({name:String,age:Number,hobbies:[String]
})
// 使用规则创建集合:两个参数,集合名称,创建集合规则
const User = mongoose.model('User',userSchema) //users// find()方法查询返回的结果都是数组
// // 查询用户集合中的所有文档
// User.find().then(result => console.log(result))// // 查询name="falcon"的用户信息
// User.find({name:'falcon'}).then(result => console.log(result))// findOne 返回一条文档,返回一个对象
// // 默认返回当前集合中的第一条数据
// User.findOne().then(result => console.log(result))// // 查找age=18的数据对象
// User.findOne({age:18}).then(result => console.log(result))// // 条件查询:大于、小于
// User.find({age:{$gt:16,$lt:20}}).then(result => console.log(result))// // 查询包含
// User.find({hobbies:{$in:['singing']}}).then(result => console.log(result))// // 选择要查询的字段
// User.find().select('name hobbies').then(result => console.log(result))// // 除去默认带的id属性
// User.find().select('name hobbies -_id').then(result => console.log(result))// // 按照年龄进行排序(默认为升序)
// User.find().sort('age').then(result => console.log(result))// // 按照年龄降序进行排序
// User.find().sort('-age').then(result => console.log(result))// // skip跳过多少条数据 limit限制查询数据(意思是略过第一条,连续查询两条)
// User.find().skip(1).limit(2).then(result => console.log(result))// // 查找到一条文档并删除,返回删除文档。 删除name=falcon的文档
// Course.findOneAndDelete({}).then(result => console.log(result))// // 删除多条数据。如果条件为空,则所有的数据都要删除
// // 返回结果: { n: 1, ok: 1, deletedCount: 1 }
// User.deleteMany({age:16}).then(result => console.log(result))  // 更改单个文档,返回一个promise对象。返回结果:{ n: 1, nModified: 1, ok: 1 }
// User.updateOne({name:'falcon'},{name:'Eileen'}).then(result => console.log(result))
// User.updateOne({name:'alice'}).then(result => console.log(result))// 更新多个文档,第一个为查询条件,不传对象或者传空值,默认更改所有的,返回一个promise对象。返回结果:{ n: 3, nModified: 1, ok: 1 }
User.updateMany({name:'Eileen'},{name:'rose'}).then(result => console.log(result))
mongoose验证

// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{useNewUrlParser: true,useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))// 创建集合规则
const postSchema = new mongoose.Schema({title:{type:String,// required:truerequired:[true,'请传输标题信息'],minlength:[2,'长度不得少于两位'],maxlength:[5,'长度不能超过五位'],// trim 去除首尾的空格trim:true},age:{type:Number,min:[16,'年龄不得小于16岁'],max:[80,'年龄不得大于80岁']},publishDate:{type:Date,default:Date.now},category:{type:String,// 枚举 列举出当前字段可以赋值的范围// enum:['html','css','javascript','node.js']enum:{values:['html','css','javascript','node.js'],message:'分类名称要在指定范围内'}},author:{type:String,validate:{validator:v =>{// 返回一个布尔值,true,验证成功;false,验证失败。v要验证的值return v && v.length > 4},// 自定义错误信息message:'传入的值不符合验证规则'}}
})
// 创建集合
const Post = mongoose.model('Post',postSchema) //posts// 向当前集合中插入数据
// Post.create({title:'    aa      '}).then(result => console.log(result)) //{ _id: 5f8e3682d7fe2d42bcbe34a2, title: 'aa', __v: 0 }
// Post.create({title:'    a  a      '}).then(result => console.log(result)) //{ _id: 5f8e3699463f101dac905728, title: 'a  a', __v: 0 }
Post.create({title:'cc',age:13,category:'java',author:'a'})
.then(result => console.log(result))
.catch(error => {// 获取错误信息对象const err = error.errors// 循环错误信息对象for(var attr in err){console.log(err[attr]['message']);}
})// 删除
// Post.deleteMany({}).then(result => console.log(result))
集合关联


// 引入操作MongoDB的第三方包mongoose
const mongoose = require('mongoose')
const { title } = require('process')
// 建立数据库的连接
mongoose.connect('mongodb://localhost/dbDemo',{useNewUrlParser: true,useUnifiedTopology: true
})
.then(() => console.log('数据库连接成功!'))
.catch(err => console.log(err,'数据库连接失败!'))// 用户集合规则
const userSchema = new mongoose.Schema({name:{type:String,required:true}
})
// 文章集合规则
const postSchema = new mongoose.Schema({title:{type:String},// *1.将文章集合和用户集合关联author:{type:mongoose.Schema.Types.ObjectId,ref:'User'}
})// 创建用户集合
const User = mongoose.model('User',userSchema) //users
// 创建文章集合
const Post = mongoose.model('Post',postSchema) //posts// 创建用户
// User.create({name:'falcon'}).then(result => console.log(result))
// 创建文章
// Post.create({title:'123',author:'5f8e417419d60e49b01044da'}).then(result => console.log(result))// *2.查询发布文章的author信息
Post.find().populate('author').then(result => console.log(result))

11.模板引擎

第三方模块,让开发者以更加友好的方式拼接字符串,使代码更清晰和易于维护

art-template

  1. 命令行中使用npm install art-template安装
  2. 使用const template = require('art-template')引入模块引擎
  3. 告诉模板引擎要拼接的数据和模板:const html = template('模板路径',数据)
//app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')// 模板路径要用绝对路径
const views = path.join(__dirname,'views','index.art')
const html = template(views,{name:'falcon',age:20
})
console.log(html);
<!-- index.art -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body>{{name}}{{age}}
</body>
</html>

运行app.js后的结果:

语法

标准语法
  1. 输出 {{ 数据 }}
  2. 原文输出 {{ @数据 }}
  3. 条件判断:{{if 条件}} ... {{/if}} {{if v1}} ... {{else if v2}} ... {{/if}}
  4. 循环:{{each target}} {{$index}} {{$value}} {{/each}}
  5. 子模板:使用子模板可将网站公共区块(头部、底部)抽离到单独的文件中 {{include '模板(路径)'}}
  6. 模板继承:使用模板继承可以将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件
    (1)向模板中导入变量:template.defaults.imports.变量名 = 变量值
    (2)设置模板根目录:template.defaults.root = 模板目录
    (3)设置模板默认后缀:template.defaults.extname = '.art'
原始语法
  1. 输出 <%=数据 %>
  2. 原文输出 <%-数据 %>
  3. 条件判断:<% if(value){ %> ... <% } %> <% if(v1){ %> ... <% }else if(v2){ %> ... <% } %>
  4. 循环:<% for(var i = 0;i < target.length;i++){ %> <%= i %> <%= target[i] %> <% } %>
  5. 子模板:<% include('模板(路径)') %>
  6. 模板继承
    1-5语法规则案例:
// template/app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')// 模板路径要用绝对路径
const views = path.join(__dirname,'views','index.art')
const html = template(views,{name:'falcon',age:20,sex:'男',content:'<h3>hello world</h3><p>love me love my dog</p>',user:[{"name":"falcon","age":20,"password":"111111","email":"123@163.com",},{"name":"alice","age":18,"password":"222222","email":"124@163.com",},{"name":"lily","age":21,"password":"333333","email":"125@163.com",},{"name":"rose","age":16,"password":"555555","email":"126@163.com",}],msg:'welcome to home page'
})
console.log(html);
<!-- template/views/index.art -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 标准语法 --><!-- 1.输出 -->{{name}}{{age}}<!-- 2.原文输出 -->{{@ content}}<!-- 3.判断 -->{{if age===20}}<h3>you are right</h3>{{/if}}{{if age===20}}<h3>give me five</h3>{{else if age===21}}<h3>try again</h3>{{/if}}<!-- 4.循环 -->{{each user}}<li>{{$value.name}}</li><li>{{$value.age}}</li><li>{{$value.password}}</li><li>{{$value.email}}</li>{{/each}}<!-- 5.子模板 -->{{ include './common/header.art' }}<div>{{msg}}</div>{{ include './common/footer.art' }}<!-- 原始语法 --><!-- 1.输出 --><%= name %><%= age %><!-- 2.原文输出 --><%- content %><!-- 3.判断 --><% if(age === 20){ %><h3>bingo</h3><% } %><% if(sex === '女'){ %><h3>beautiful</h3><% }else if(sex === '男'){ %><h3>handsome</h3><% } %><!-- 4.循环 --><% for(var i = 0;i < user.length; i++){ %><li><%= i %><%= user[i].name %><%= user[i].age %><%= user[i].password %><%= user[i].email %></li><% } %><!-- 5.子模板 --><% include ('./common/header.art') %><div>{{msg}}</div><% include ('./common/footer.art') %>
</body>
</html>
<!-- template/views/common/header.art -->
这是头部
<!-- template/views/common/footer.art -->
这是尾部

6.模板继承案例:

// template/app.js
// 导入模板引擎
const template = require('art-template')
// 引入path模块
const path = require('path')
// 引入dateformat模块。时间格式化处理:1.安装dateformat 2.将模板引入进来 3.使用模板进行时间格式化
const dateFormat = require('dateformat')// 模板路径要用绝对路径
// const views = path.join(__dirname,'views','index.art')
// const views = path.join(__dirname,'views','inherit.art')// 设置模板根目录
template.defaults.root = path.join(__dirname,'views')
// 设置模板默认后缀
template.defaults.extname = '.art'// 导入模板变量
template.defaults.imports.dateFormat = dateFormat// const html = template(views,{// 设置根目录之后,只需要填模板名称即可
// const html = template('inherit.art',{// 设置模板默认后缀之后,只需要填模板名称即可
const html = template('inherit',{msg:'welcome to home page',time:new Date()
})
console.log(html);
<!-- template/views/inherit.art -->
<p>{{ msg }}</p>
<p>{{dateFormat(time,'yyyy-MM-dd HH:mm:ss')}}</p>
<!-- template/views/common/layout.art -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>{{block 'link'}} {{/block}}
</head>
<body>{{block 'content'}} {{/block}}
</body>
</html>

静态资源访问处理

12.Express框架

特点

  1. 提供了方便简洁的路由定义方式
  2. 对获取HTTP请求参数进行了简化处理
  3. 对模板引擎的支持程度高,方便渲染动态HTML页面
  4. 提供了中间件机制有效控制HTTP请求
  5. 拥有大量第三方中间件对功能进行扩展
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/',(req,res) => {// res.send('hello world')res.send({'name':'falcon','age':20})
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

中间件

  1. 中间件就是一堆方法,可以接受客户端发来的请求、可以对请求作出响应,也可以将请求继续教给下一个中间件处理
  2. 可以对同一个请求设置多个中间件,对同一个请求进行多次处理
  3. 可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件
    两部分组成:中间件方法 和 请求处理函数
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/request',(req,res,next) => {req.name = 'falcon',next()
})
app.get('/request',(req,res) => {res.send(req.name)    //falcon
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
app.use中间件

// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()// app.use 接受所有请求的中间件
app.use((req,res,next) => {console.log('这是app.use中间件');next()
})
// 当客户端访问 /request 请求的时候走当前中间件
app.use('/request',(req,res,next) => {console.log('这是app.use 固定请求地址中间件');next()
})// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/',(req,res) => {res.send('home page')
})
app.get('/request',(req,res,next) => {req.name = 'falcon',next()
})
app.get('/request',(req,res) => {res.send(req.name)    //falcon
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');
中间件的应用

// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()app.use('/admin',(req,res,next) => {// 设置登录状态// let isLogin = falselet isLogin = trueif(isLogin){next()}else{res.send('你还没登录,不能进行访问')}
})// 处理客户端发送的请求
// send即可以传字符串,也可以传json对象
app.get('/admin',(req,res,next) => {res.send('已登录,可访问')
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');


只需要在1.路由保护的app.use最前面加上一个app.use(接受所有的请求)

app.use((req,res,next) => {res.send('网站正在维护,请稍后再试')
})


在1.路由保护的基础上,在请求的最后,加上一个app.use接受所有请求的中间件

// 自定义404页面
app.use((req,res,next) => {// 默认的状态码为200,设置为404res.status(404).send('当前访问的页面是不存在的')
})
错误处理中间件

// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()// 请求抛出一个错误
app.get('/index',(req,res) => {throw new Error('这是一个错误')
})// 错误处理中间件
app.use((err,req,res,next) => {res.status(500).send(err.message)
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

// 引入express框架
const express = require('express')
// 引入读取文件模块
const fs = require('fs')
// 创建网站服务器
const app = express()// 请求抛出一个错误
app.get('/index',(req,res,next) => {fs.readFile('./demo.txt','utf8',(err,result) => {if(err != null){//读取失败next(err)}else{//文件读取成功res.send(result)}})
})// 错误处理中间件
app.use((err,req,res,next) => {res.status(500).send(err.message)
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

捕获错误


// 引入express框架
const express = require('express')
// 引入promisify
const promisify = require('util').promisify
// 包装readFile方法
const readFile = promisify(fs.readFile)
// 创建网站服务器
const app = express()app.get('/index',async (req,res,next) => {// 进行错误的捕获try{await readFile('./demo.txt')}catch(ex){next(ex)}
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

构建模块化路由


// route/home.js
// 引入express框架
const express = require('express')// 创建路由对象
const home = express.Router()// 路由对象处理
home.get('/index',(req,res) => {res.send('welcome to home page')
})// 将路由对象导出
module.exports = home;
// route/admin.js
// 引入express框架
const express = require('express')// 创建路由对象
const admin = express.Router()// 路由对象处理
admin.get('/index',(req,res) => {res.send('welcome to admin page')
})// 将路由对象导出
module.exports = admin;
// router.js
// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()
// 导入home路由模块
const home = require('./router/home')
// 导入admin路由模块
const admin = require('./router/admin')// 使用home路由
app.use('/home',home)
// 使用admin路由
app.use('/admin',admin)// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');

GET、POST参数的获取

GET参数的获取

// 引入express框架
const express = require('express')
// 创建网站服务器
const app = express()// 响应客户端的请求
app.get('/index',(req,res) => {// 获取get请求参数res.send(req.query)
})// 监听端口
app.listen(3000)
console.log('服务器启动成功!');
POST参数的获取

//post.js
// 引入express框架
const express = require('express')
// 引入body-parser模块
const bodyParser = require('body-parser')
// 创建web服务器
const app = express()// 拦截所有的请求
// extended:false 方法内部使用querystring模块处理请求参数的格式;extended:true 方法内部使用第三方模块qs处理参数的请求格式
app.use(bodyParser.urlencoded({extended:false}))// 处理客户端的请求
app.post('/add',(req,res) => {res.send(req.body)
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');
<!-- post.html -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>post参数的获取</title>
</head>
<body><form action="http://localhost:3000/add" method="POST"><input type="text" name="username" id=""><input type="password" name="password" id=""><input type="submit" value="提交"></form>
</body>
</html>

Express路由参数

// 引入express框架
const express = require('express')
// 创建web服务器
const app = express()// 处理客户端的请求
app.get('/index/:id/:name/:age',(req,res) => {res.send(req.params)
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');

静态资源的处理

// 有一个和static.js平级的public文件夹,用于存放静态资源
// 引入express框架
const express = require('express')
// 引入path模块
const path = require('path')
// 创建web服务器
const app = express()// 实现静态资源的访问
app.use(express.static(path.join(__dirname,'public')))// 监听一个端口
app.listen(3000)
console.log('服务器启动成功!');

模板引擎



然后需要在和template.js平级的目录中新建一个views文件夹,里面存放需要访问的 ‘.art’ 后缀的文件

// template.js
// 引入express框架
const express = require('express')
// 引入path模块
const path = require('path')
// 创建web服务器
const app = express()// 1.告诉express框架使用什么模板引擎渲染什么后缀的模板文件:1模板的后缀;2使用的模板引擎
app.engine('art',require('express-art-template'))
// 2.告诉express框架模板存放的位置是什么
app.set('views',path.join(__dirname,'views'))
// 3.告诉express框架模板的默认后缀是什么
app.set('view engine','art')app.get('/index',(req,res) => {// res.render做了很多事情:1、拼接模板路径;2、拼接模板后缀;3、告诉模板引擎哪一个模板和哪一个数据进行拼接;4、把拼接的结果响应给客户端res.render('index',{msg:'hello world'})
})app.get('/list',(req,res) => {res.render('list',{msg:'list page'})
})// 监听一个端口
app.listen(3000)
console.log('服务器启动成功');

app.locals对象

将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到

// app.locals 所有模板都可以获取到数据
// 在上面代码的基础上添加一个app.locals,则在views文件夹里面的.art文件都可以访问app.locals中所包含的文件
app.locals.users = [{name:'falcon',age:20
},{name:'rose',age:18
}]
<ul>{{each users}}<li>{{$value.name}}{{$value.age}}</li>{{/each}}
</ul>

前后端交互node服务器相关推荐

  1. 前后端交互ajax和axios入门讲解,以及http与服务器基础

    ajax和http小白入门,客户端与服务器基础讲解,前后端交互(从入门到实践详细解析) 文章目录 ajax和http小白入门,客户端与服务器基础讲解,前后端交互(从入门到实践详细解析) 前言 一.Aj ...

  2. 小程序服务器搭建前后端交互,微信小程序:request前后端交互 路由跳转 存储数据到本地和获取 小程序登入 授权...

    一 request前后端交互 基本样式 wx.request({ url:'test.php', //仅为示例,并非真实的接口地址 data: { x:'', y:''}, header: {'con ...

  3. 服务器版博客系统、前后端交互1

    一.准备工作 1). 创建 maven 项目 2). 引入依赖 servlet,jackson,mysql <dependencies><!-- https://mvnreposit ...

  4. ajax+node前后端交互学习笔记(1)

    大致理解前后端交互的概念 当你去餐馆吃饭的时候,坐下后服务员会带着⼀个菜单过来,问你需要点什么菜,这个时候你浏览了 菜单上的菜,把想吃的菜告诉服务员,服务员把你点的菜拿到后台,后台根据你点的菜名,逐⼀ ...

  5. vue+node.js前后端交互中的token令牌验证

    这篇文章分享一下本人学习vue+node.js前后端交互中的登录token令牌的心得 最近准备写一个个人博客网站,前端采用的是vue+element,后端用node.js 在做用户登录的时候就想到 如 ...

  6. 前后端交互,网络请求

    这边文章主要根据我自己的前端开发工作经验,东拼西凑出来的一点理解,希望能够对大家有点帮助,如果有误导或者错误的地方还请帮助指正,感谢!!! 前后端交互我理解主要分为三个主要的部分: 1.客户端 2.服 ...

  7. [原创]前后端交互的方式整理

    前言 本来我只是想整理下前后端如何传输数据这种交互过程,大概流程如下: 前台使用ajax通过get/post等方式提交数据到后端 后端如何获取参数 经过业务处理后,返回前端对应的响应数据 前端接受到响 ...

  8. 写给刚入门的前端工程师的前后端交互指南

    转自原文 写给刚入门的前端工程师的前后端交互指南 作为刚接触前端的不久的童鞋,大家都会兴奋于CSS和JS所带来漂亮界面,然而,前端工程师除了UI重构外,还有非常重要的职责在正确的区域渲染出服务端的数据 ...

  9. 微信小程序 09 前后端交互

    9.1 前后端交互 首先 我们 要 在 安装了 node.js 的环境下 安装 nodemon 这个插件. npm install -g nodemon 2. 修改 npm 和 npm.cmd 两个 ...

最新文章

  1. Linux内核源码结构
  2. 防火墙(12)——查看协议被连接的次数、通过连接状态来写规则
  3. tensorflow综合示例4:逻辑回归:使用Estimator
  4. MongoDB两阶段提交实现事务
  5. ffmpeg rtmp 推流错误WriteN, RTMP send error 10053 10038
  6. viewpager初始化fragment没有绘制_NDK OpenGL ES渲染系列 之 绘制三角形
  7. 全向轮机器人应用平台
  8. 终极算法——第五章:进化学派:自然的学习算法
  9. 立创EDA学习笔记(3)——创建元件封装
  10. centos检测不到磁盘_CentOS下磁盘坏道的检测及修复
  11. word安全模式解除
  12. 计算机制作贺卡教案,教案与学生成果:制作电子贺卡
  13. 给博士一年级新生的建议!
  14. 在线的色值转换RGB网址
  15. linux系统设置密钥登录
  16. Redis——发布/订阅
  17. CVP0.M24、CVP0.M28、CVZ0.S08插装式单向阀
  18. 医疗器械软件注册 - 基本概念
  19. TensorFlow: A System for Large-Scale Machine Learning翻译
  20. linux命令行开头是sh,shell脚本语言的使用(超全超详细)

热门文章

  1. 软件测试实验过程记录
  2. Java实现图片压缩且不改变原图尺寸
  3. php怎么让页面下雪花,html5实现下雪效果的方法
  4. 芯片短缺困局难解汽车巨头被迫停工减产---道合顺大数据
  5. 前端二面必会面试题(附答案)
  6. android11升级名单vivo,vivo新系统升级名单已经公布,第一批11部手机入选
  7. 英语,程序员永远的痛???//“不要倒在起跑线上”课程介绍
  8. wifidog 配置文件
  9. 公众平台 python_微信公众平台SDK Python
  10. java如何用雪花算法批量生成唯一编码(保证位数不过长)?