前后端交互node服务器

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).pathname
  pathname = 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为null
  fs.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:true
    required:[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 = false
  let isLogin = true

  if(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,设置为404
  res.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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值