三、MongoDB数据库、Express框架、AJAX

1. MongoDB数据库

1.1 什么是数据库

数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储。它是独立于语言之外的软件,可以通过API去操作它。常见的数据库软件有:mysql、mongoDB、oracle、sqlserver。

1.2 MongoDB数据库下载安装

下载地址:MongoDB Community Download | MongoDB

MongoDB可视化软件下载地址:MongoDB Compass Download | MongoDB

MongoDB数据库工具下载地址:Download MongoDB Command Line Database Tools | MongoDB

1.3 数据库相关概念

在一个数据库软件中可以包含多个数据仓库,在每个数据仓库中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)。

术语 解释说明
database 数据库,mongoDB数据库软件中可以建立多个数据库
collection 集合,一组数据的集合,可以理解为JavaScript中的数组
document 文档,一条具体的数据,可以理解为JavaScript中的对象
field 字段,文档中的属性名称,可以理解为JavaScript中的对象属性

1.4 Mongoose第三方包

使用Node.js操作MongoDB数据库需要依赖Node.js第三方包mongoose

使用npm install mongoose命令下载

1.5 启动MongoDB

在命令行工具中运行net start mongoDB即可启动MongoDB,否则MongoDB将无法连接。也可以直接打开数据库软件启动MongoDB。

1.6 数据库连接

使用mongoose提供的connect方法即可连接数据库。

mongoose.connect('mongodb://localhost/playground',{ 
useNewUrlParser: true,
useUnifiedTopology: true }).then(() => 
console.log('数据库连接成功')).catch(err => 
console.log('数据库连接失败', err));

1.7 创建数据库

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

1.8 MongoDB增删改查操作

1.8.1创建集合

创建集合分为两步,一是对集合设定规则,二是创建集合,通过mongoose.Schema构造函数的实例即可创建集合。

// 设定集合规则
const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});
// 创建集合并应用规则
const Course = mongoose.model('Course', courseSchema);  // courses

1.8.2 创建文档

创建文档实际上就是向集合中插入数据。

分为两步:

1.创建集合实例。

2.调用实例对象下的save方法将数据保存到数据库中。

// 创建集合实例
const course = new Course({
   name: '张三',
   age: '24',
   sex: '男',
});
// 将数据保存到数据库中
course.save(function(err,result){
​ // save方法,通过回调函数,返回添加的结果
​    if(!err){
​    console.log(result);
​    }
});
// 根据表对象,创建一个文档对象,并将该文档对象保存到数据库的数据表中(回调函数方式)
Course.create({name: '张三', age: '24',sex: '男'}, (err, doc) => {
                // 错误对象
                console.log(err);
               // 当前插入的文档
                console.log(doc);
});
//根据表对象,创建一个文档对象,并将该文档对象保存到数据库的数据表中(Promise方式)
Course.create({name: '张三', age: '24',sex: '男'})
.then(doc => console.log(doc)).catch(err => console.log(err))

1.8.3 mongoDB数据库导入数据

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

找到mongodb数据库的安装目录,将安装目录下的bin目录放置在环境变量中。

1.8.4 查询文档

// 根据条件查找文档(条件为空则查找所有文档)// 返回文档集合
Course.find().then(result => console.log(result))
// 匹配大于 小于
// age:{$lt:30,$gt:18} 不包括18和30
// age:{$lte:30,$gte:18} 包括18和30
User.find({age: {$gt: 20, $lt: 50}}).then(result => console.log(result))
// 匹配包含
User.find({hobbies: {$in: ['敲代码','学习']}}).then(result => console.log(result))
User.find({hobbies: {$all: ['敲代码','学习']}}).then(result => console.log(result))
// 根据条件查找文档 // 返回文档
Course.findOne({name: 'node.js基础'}).then(result => console.log(result))
// $regex用于设置正则表达式搜索
// 通过select方法,限定查询哪些列,默认情况_id都会返回,
// 如果不需要,通过-_id的方式去掉
User.find({name:{$regex:/刘/i}}).select('name sex age -_id').then(result=>{
console.log(result);
})
// 选择要查询的字段
User.find().select('name email').then(result => console.log(result))
// 将数据按照年龄进行排序
User.find().sort('age').then(result => console.log(result))
// 先根据性别升序,再根据年龄降序
User.find().sort('sex -age').then(result => console.log(result))
// skip 跳过多少条数据 limit 限制查询数量
User.find().skip(2).limit(2).then(result => console.log(result))

1.8.5 删除文档

// 删除单个
Course.deleteOne({}).then(result => console.log(result))
// 删除多个
User.deleteMany({}).then(result => console.log(result))

1.8.6 更新文档

// 更新单个
User.updateOne({查询条件}, {要修改的值}).then(result => console.log(result))
// 更新多个
User.updateMany({查询条件}, {要更改的值}).then(result => console.log(result))

1.8.7 mongoose验证

在创建集合规则时,可以设置当前字段的验证规则,验证失败就输入插入失败。

1.required: true 必需要传字段

2.minlength:3 字符串最小长度

3.maxlength: 20 字符串最大长度

4.min: 2 数值最小为2

5.max: 100 数值最大为100

6.enum: ['html', 'css', 'javascript', 'node.js']

7.trim: true 去除字符串两边的空格

8.validate: 自定义验证器

9.default: 默认值

获取错误信息:error.errors['字段名称'].message

1.8.8 集合关联

通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用到集合关联。

1.使用id对集合进行关联

2.使用populate方法进行关联集合查询

// 用户集合
const User = mongoose.model('User', new mongoose.Schema({ name: { type: String } }));
// 文章集合
const Post = mongoose.model('Post', new mongoose.Schema({
         title: { type: String },
        // 使用ID将文章集合和作者集合进行关联
        author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
}));
//联合查询
Post.find().populate('author').then((err, result) => console.log(result));
// 01.导入mongoose包
const mongoose = require('mongoose')
// 02.使用mongoose提供的connect方法即可连接数据库
mongoose.connect('mongodb://localhost/myschool').then(()=>{
    console.log('数据库连接成功')
}).catch(err=>{
    console.log('数据库连接失败', err)
})
// 03.创建一个表规范
const studentSchema = new mongoose.Schema({
    name:String,
    age:Number,
    sex:String
})
// 04.根据表规范,创建表
// 注意:数据库中会创建一个名为“students”的表
const Student = mongoose.model('Student',studentSchema) 
/* // 05.创建文档,就是创建一个表里面的数据
let stu1 = new Student({
    name:'张三',
    age:20,
    sex:'男'
})
// 06.将文档对象添加到数据表中(就是将数据保存到数据库中)
stu1.save(function(err,result){
    if(!err){
        console.log(result);
    }
}) */

// 创建文档和保存文档这两个步骤可以合并,通过:表对象.create()方法
Student.create({
    name:'李四',
    age:30,
    sex:'女'
}).then(r=>{
    console.log(r);
}).catch(err=>{
    console.log(err);
})
// 添加操作
// 01.导入mongoose包
const mongoose = require('mongoose')
// 02.使用mongoose提供的connect方法即可连接数据库
mongoose.connect('mongodb://localhost/myschool').then(()=>{
    console.log('数据库连接成功')
}).catch(err=>{
    console.log('数据库连接失败', err)
})
// 03.创建一个表规范
const studentSchema = new mongoose.Schema({
    name:String,
    sex:String,
    age:Number,
    hobbies:Array,
    email:String,
    isVIP:Boolean
})
// 04.根据表规范,创建表
const Student = mongoose.model('Student',studentSchema)

// 05.向数据库中添加数据
Student.create({
    name:'小明',
    sex:'女',
    age:22,
    hobbies:['演戏','睡觉'],
    email:'[email protected]',
    isVIP:false
}).then(r=>{
    console.log(r);
}).catch(err=>{
    console.log(err);
})
// 查询操作
// 01.导入mongoose包
const mongoose = require('mongoose')
// 02.使用mongoose提供的connect方法即可连接数据库
mongoose.connect('mongodb://localhost/myschool').then(()=>{
    console.log('数据库连接成功')
}).catch(err=>{
    console.log('数据库连接失败', err)
})
// 03.创建一个表规范
const studentSchema = new mongoose.Schema({
    name:String,
    sex:String,
    age:Number,
    hobbies:Array,
    email:String,
    isVIP:Boolean
})
// 04.根据表规范,创建表
const Student = mongoose.model('Student',studentSchema)

// 05.查询
// 1. 根据条件查找文档(条件为空则查找所有文档)
// find()方法的返回值是数组
/* Student.find().then(r=>{
    console.log(r);
}) */
/* Student.find({name:'周杰伦1'}).then(r=>{
    console.log(r);
}) */

// 2. 根据条件查找一个文档(条件为空返回第一个文档)
// findOne()方法的返回值是对象
/* Student.findOne().then(r=>{
    console.log(r);
}) */
/* Student.findOne({name:'周杰伦'}).then(r=>{
    console.log(r);
}) */

// 3. 如果实现模糊查询
// 3.1. 匹配大于 小于
// 查询年龄大于30岁的学生信息
/* Student.find({age:{$gt:30}}).then(r=>{
    console.log(r);
}) */
// 查询年龄小于20岁的学生信息
// Student.find({age:{$lt:20}}).then(r=>{
//     console.log(r);
// })
// 查询年龄在20到40之间的学生信息
// $gt 是大于 $gte 是大于等于
// $lt 是小于 $lte 是小于等于
/* Student.find({age:{$gte:20,$lte:40}}).then(r=>{
    console.log(r);
}) */

// 3.2. $regex用于设置正则表达式搜索
/* Student.find({name:{$regex:/杰/}}).then(r=>{
    console.log(r);
}) */

// 3.3. 匹配包含(数组元素是否包含)
// $in 用于匹配数组中是否有指定的元素(是或者关系)
/* Student.find({hobbies:{$in:['学习','唱歌']}}).then(r=>{
    console.log(r);
}) */
// $all 用于匹配数组中是否有指定的元素(是并且关系)
/* Student.find({hobbies:{$all:['写歌','唱歌']}}).then(r=>{
    console.log(r);
}) */

// 4. 查询指定列
// select()方法,用于查找指定的列,-_id表示查询列中去除_id列
/* Student.find().select('name sex age -_id').then(r=>{
    console.log(r);
}) */

// 5. 对查询结果排序
// sort()方法,用于根据指定列排序
/* Student.find().select('name sex age -_id').sort('age').then(r=>{
    console.log(r);
}) */
// sort()方法里面的列名,加上减号表示降序
/* Student.find().select('name sex age -_id').sort('-age').then(r=>{
    console.log(r);
}) */
// 同时根据姓名和年龄排序
// 这里是先根据性别排序,性别相同的再根据年龄降序
/* Student.find().select('name sex age -_id').sort('sex -age').then(r=>{
    console.log(r);
}) */

// 6. 分页查询
//  skip 跳过多少条数据 limit 限制查询数量
let pageIndex=3   //页码
let pageSize=2    //每页数量
Student.find().select('name sex age -_id').skip((pageIndex-1)*pageSize).limit(pageSize).then(r=>{
    console.log(r);
})
// 修改和删除操作

// 01.导入mongoose包
const mongoose = require('mongoose')
// 02.使用mongoose提供的connect方法即可连接数据库
mongoose.connect('mongodb://localhost/myschool').then(() => {
    console.log('数据库连接成功')
}).catch(err => {
    console.log('数据库连接失败', err)
})
// 03.创建一个表规范
const studentSchema = new mongoose.Schema({
    name: String,
    sex: String,
    age: Number,
    hobbies: Array,
    email: String,
    isVIP: Boolean
})
// 04.根据表规范,创建表
const Student = mongoose.model('Student', studentSchema)

// 更新操作
// 1. 更新单个
/* Student.updateOne({_id:"61d7aa96c539753f60468bcb"},{
    name:'张三',
    age:38,
}).then(r=>{
    console.log(r);
}) */

// 2. 更新多个
/* Student.updateMany({sex:'女'},{age:18}).then(r=>{
    console.log(r);
}) */

// 删除操作
// 1. 删除单个
/* Student.deleteOne({_id:'61d7aa96c539753f60468bcb'}).then(r=>{
    console.log(r);
}) */

// 2. 删除多个
Student.deleteMany({ sex: '女' }).then(r => {
    console.log(r);
})

2.Express框架

2.1 Express框架是什么

Express是一个基于Node平台的web应用开发框架,它提供了一系列的强大特性,帮助你创建各种Web应用。我们可以使用 npm install express 命令进行下载。

Express框架特性:

1.提供了方便简洁的路由定义方式

2.对获取HTTP请求参数进行了简化处理

3.对模板引擎支持程度高,方便渲染动态HTML页面

4.提供了中间件机制有效控制HTTP请求

5.拥有大量第三方中间件对功能进行扩展

2.2 路由

// 当客户端以get方式访问/时
app.get('/', (req, res) => {
   // 对客户端做出响应
   res.send('Hello Express');
});
// 当客户端以post方式访问/add路由时
app.post('/add', (req, res) => {
   res.send('使用post方式请求了/add路由');
});
// 所有方式,优先级最高
app.all('/add',(req,res)=>{
  res.send('使用get/post方式请求了/add路由');
})

2.3 请求参数

app.get('/', (req, res) => {
   // 获取GET参数
    console.log(req.query);
});
app.post('/', (req, res) => {
   // 获取POST参数
    console.log(req.body);
})

2.4 Express初体验

使用Express框架创建web服务器及其简单,调用express模块返回的函数即可。

// 引入Express框架
const express = require('express');
// 使用框架创建web服务器
const app = express();
// 当客户端以get方式访问/路由时
app.get('/', (req, res) => {
   // 对客户端做出响应 send方法会根据内容的类型自动设置请求头
    res.send('Hello Express'); 
});
// 程序监听3000端口
app.listen(3000,()=>{console.log('服务已经启动,端口号3000')});

2.5 中间件 

2.5.1 什么是中间件

中间件就是一堆方法,可以接收客户端发来的请求、可以对请求做出响应,也可以将请求继续交给下一个中间件继续处理。中间件主要由两部分构成,中间件方法以及请求处理函数。

中间件方法由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。

app.get('请求路径', '处理函数') // 接收并处理get请求

app.post('请求路径', '处理函数') // 接收并处理post请求

可以针对同一个请求设置多个中间件,对同一个请求进行多次处理。默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配。

可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件。

app.get('/request', (req, res, next) => {
    req.name = "张三";
    next();
});
app.get('/request', (req, res) => {
   res.send(req.name);
});

2.5.2 app.use中间件用法

app.use 匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求。

app.use((req, res, next) => {
  console.log(req.url);
  next();
});

app.use 第一个参数也可以传入请求地址,代表不论什么请求方式,只要是这个请求地址就接收这个请求。

app.use('/admin', (req, res, next) => {
     console.log(req.url);
     next();
});

2.5.3 中间件应用

1.路由保护,客户端在访问需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应,禁止用户进入需要登录的页面。

2.网站维护公告,在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中。

3.自定义404页面。

2.5.4 错误处理中间件

在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败。错误处理中间件是一个集中处理错误的地方。

app.use((err, req, res, next) => {
  res.status(500).send('服务器发生未知错误');
})

当程序出现错误时,调用next()方法,并且将错误信息通过参数的形式传递给next()方法,即可触发错误处理中间件。

app.get("/", (req, res, next) => {
     fs.readFile("/file-does-not-exist", (err, data) => {
​                if (err) {
​                  next(err);
​                }
    });
});

2.5.5 捕获错误

在node.js中,异步API的错误信息都是通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。异步函数执行如果发生错误要如何捕获错误呢?

try catch 可以捕获异步函数以及其他同步代码在执行过程中发生的错误。

app.get("/", async (req, res, next) => {
    try {
​         await User.find({name: '张三'})
      } catch(ex) {
​        next(ex);
   }
});

2.6 构建模块化路由

const express = require('express')
const home = express.Router(); // 创建路由对象
app.use('/home', home);  // 将路由和请求路径进行匹配
home.get('/index', () => {   // 在home路由下继续创建路由
   res.send('欢迎来到博客展示页面'); // /home/index
});
const home = express.Router();  // home.js
home.get('/index', () => {
  res.send('欢迎来到博客展示页面');
});
module.exports = home;
const admin = express.Router(); // admin.js
admin.get('/index', () => {
   res.send('欢迎来到博客管理页面');
});
module.exports = admin;
const home = require('./route/home.js');  // app.js
const admin = require('./route/admin.js');
app.use('/home', home);
app.use('/admin', admin);

2.7 参数

2.7.1 GET参数的获取

Express框架中使用req.query即可获取GET参数,框架内部会将GET参数转换为对象并返回。

// 接收地址栏中问号后面的参数    // 例如: http://localhost:3000/?name=zhangsan&age=30

app.get('/', (req, res) => {
   console.log(req.query); // {"name": "zhangsan", "age": "30"}
});

2.7.2 POST参数的获取

旧版本的Express中接收post请求参数需要借助第三方包 body-parser。

const bodyParser = require('body-parser'); // 引入body-parser模块
app.use(bodyParser.json()); // 配置body-parser模块 // 设置允许接收json格式的数据
app.use(bodyParser.urlencoded({ extended: false })); // 设置允许接收urlencoded格式的数据

新版本的Express不需要借助第三方包 body-parser 

app.use(express.json()) // 设置允许接收json格式的数据
app.use(express.urlencoded({extended:false})) // 设置允许接收urlencoded格式的数据
app.post('/add', (req, res) => {  // 接收请求
        // 接收请求参数
    console.log(req.body);
})

2.7.3 Express路由参数

app.get('/find/:id', (req, res) => {
     console.log(req.params); // {id: 123}
});
localhost:3000/find/123

2.8 静态资源的处理

通过Express内置的express.static可以方便地托管静态文件,例如img、CSS、JavaScript 文件等。app.use(express.static('public'));

现在,public 目录下面的文件就可以访问了。

1.http://localhost:3000/images/kitten.jpg

​​​​​​​2.http://localhost:3000/css/style.css

​​​​​​​​​​​​​​3.http://localhost:3000/js/app.js

​​​​​​​​​​​​​​4.http://localhost:3000/images/bg.png

​​​​​​​​​​​​​​5.http://localhost:3000/hello.html

// 使用express框架开发后台服务器
// 1.引入Express框架
const express = require('express')
// 2.使用Express框架方法创建web服务器
const app = express()
// 3.开启服务器,并监听一个端口号
app.listen(8848,()=>{
    console.log('服务器开启成功,端口号是8848');
})
// 使用文件系统,对数据做持久化保存
const fs = require('fs')
fs.readFile('./files/data.txt',(err,bf)=>{
    //\r\n是换行符,可以简写成\n
    bf.toString().split('\r\n').forEach(r=>{
        let stu = {}
        let arr = r.split('|')
        stu.no = arr[0]
        stu.name = arr[1]
        stu.age = arr[2]
        stu.sex = arr[3]
        list.push(stu)
    })
})
//定义数据
let list = []
// 4.创建接口 (路由)
//查询学生的接口
app.get('/list',(req,res)=>{
    //req是请求对象
    //res是响应对象
    //setHeader()方法,用于设置响应头信息
    //这里是设置允许跨域请求
    res.setHeader('Access-Control-Allow-Origin','*')
    //send()方法,用于响应结果
    res.send(list)
})
//添加学生的接口
app.get('/add',(req,res)=>{
    res.setHeader('Access-Control-Allow-Origin','*')
    //获取get请求方式的参数,所有参数会保存到一个对象中
    //这里返回的是一个学生对象
    let stu = req.query
    //设置学生对象的学号
    stu.no = list.length+1
    //将学生对象添加到学生数组中
    list.push(stu)
    //整理写入到文件中的数据
    let data = '\r\n'+stu.no+'|'+stu.name+'|'+stu.age+'|'+stu.sex
    //利用文件系统,将数据添加到文件中
    fs.writeFile('./files/data.txt',data,{flag:'a'},(err)=>{
        if(!err)
            res.send(true)
        else 
            res.send(false)
    })
})
学号 姓名 性别 年龄
姓名:
性别:
年龄:
// express框架的使用
//01.导入express框架
const express = require('express')
//02.创建服务器对象
const app = express()
//03.监听一个端口号
app.listen(8848,()=>{
    console.log('服务器成功开启,端口号是8848');
})

// 设置允许接收json格式的数据
app.use(express.json())
// 设置允许接收urlencoded格式的数据
app.use(express.urlencoded({extended:false}))

//定义请求中间件,所有的请求会先由中间件拦截,验证完权限后,再放行
app.use((req,res,next)=>{
    //设置允许跨域
    res.setHeader('Access-Control-Allow-Origin','*')
    //设置允许加请求头信息
    res.setHeader('Access-Control-Allow-Headers','*')
    //必须调用了next()方法后,才会继续往后执行
    next()
})

//导出app对象
exports.app = app
// 操作数据库
// 01.导入mongoose库
const mongoose = require('mongoose')
// 02.打开数据库连接
mongoose.connect('mongodb://localhost/myschool').then(()=>{
    console.log('myschool数据库连接成功');
})
// 03.创建student表规范
const studentSchema = new mongoose.Schema({
    name:String,
    sex:String,
    age:Number,
    hobbies:Array,
    email:String,
    isVIP:Boolean
})
// 04.创建student表对象
const Student = mongoose.model('student',studentSchema)

//导出学生表对象
exports.Student = Student
// 导入服务器对象
const {app} = require('./app.js')
// 导入Student表对象
const {Student} = require('./db.js')

// 查询学生信息
app.get('/list',(req,res)=>{
    //获取参数name
    let {name} = req.query
    Student.find({name:{
        //正则表达式匹配姓名模糊查询
        $regex:new RegExp(`${name}`,'g')
    }}).then(r=>{
        res.send(r)
    })
})

// 添加学生信息
app.post('/add',(req,res)=>{
    Student.create(req.body).then(r=>{
        res.send(true)
    }).catch(err=>{
        res.send(false)
    })
})

// 删除学生信息
app.post('/delete',(req,res)=>{
    let {_id} = req.body
    Student.deleteOne({_id}).then(r=>{
        res.send(true)
    }).catch(err=>{
        res.send(false)
    })
})

//根据id返回一个学生信息
app.get('/getOne',(req,res)=>{
    let {_id} = req.query
    Student.findOne({_id}).then(r=>{
        res.send(r)
    })
})

// 根据id修改指定的学生信息
app.post('/update',(req,res)=>{
    let {_id} = req.body
    Student.updateOne({_id},req.body).then(r=>{
        res.send(true)
    }).catch(err=>{
        res.send(false)
    })
})

3.AJAX

3.1 HTTP

HTTP (hypertext transport protocol) 协议 [超文本传输协议],协议详细规定了浏览器和万维网之间相互通信的规则。

3.1.1 请求

重点是格式与参数,

行 类型(GET POST) / URL / HTTP/1.1

头 Host: baidu.com

Cookie: name=汽车

Content-type: application/x-www-form-urlencoded

User-Agent: chrome 83

空行

体 username=admin&password=admin

3.1.2 响应

行 HTTP/1.1 (200/404/403/401/500) OK

头 Content-type: text/html;charset=utf-8

Content-length: 2048

Content-encoding: gzip

空行


    
    
    
        

Ajax

3.2 同源策略

同源策略:是浏览器的一种安全策略。同源:协议、域名、端口号 必须完全相同。违背同源策略就是跨域。那么如何解决跨域:

1.JSONP:是一个非官方的跨域解决方案,只支持get请求。JSONP 就是利用script标签的跨域能力来发送请求的。比如:img link iframe script。

2.CORS:跨域资源共享。是官方的跨域解决方案。新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。

//设置响应头 设置允许跨域
response.setHeader('Access-Control-Allow-Origin','*');
//响应头 *表示所有类型的头信息都可以接受
response.setHeader('Access-Control-Allow-Headers','*');

3.3 原生AJAX

3.3.1 GET 请求

//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 初始化 设置请求方法和URL
xhr.open('GET','http://127.0.0.1:8000/server?a=100&b=200&c=300');
//3. 发送
xhr.send();
//4. 事件绑定 处理服务端返回的结果
// on  when  当....时候
// readystate 是 xhr 对象中的属性,表示状态 0 1 2 3 4
// 0 表示未初始化
// 1 表示open方法已经调用完毕
// 2 表示send方法已经调用完毕
// 3 表示服务端返回了部分的结果
// 4 表示服务端返回了所有结果
// change  改变
xhr.onreadystatechange = function(){
    //判断(服务端返回了所有结果)
    if(xhr.readyState === 4){
        //判断响应状态码 200 404 403 401 500
        //2xx 成功
        if(xhr.status >= 200 && xhr.status < 300){
            //处理结果 行 头 空行 体
            //1. 响应行
            console.log(xhr.status);    //状态码
            console.log(xhr.statusText);  //状态字符串
            console.log(xhr.getAllResponseHeaders());  //所有响应头
            console.log(xhr.response);  //响应体
            //设置 result 的文本
            result.innerHTML = xhr.response
        }else{
        }
    }
}

3.3.2 POST 请求

//1. 创建对象
const xhr = new XMLHttpRequest();
//2. 初始化 设置类型与 URL
xhr.open('POST','http://127.0.0.1:8000/server')
//设置请求头
//Content-Type 是设置请求体内容的类型
//application/x-www.form-urlencoded 是参数查询字符串的类型
//application/json 是json格式类型
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//自定义头
xhr.setRequestHeader('name','张三')
//3. 发送
xhr.send('a=100&b=200&c=300')
// xhr.send('a:100&b:200&c:300')
//4. 事件绑定
xhr.onreadystatechange = function(){
    //对状态判断
    if(xhr.readyState === 4){
        if(xhr.status >= 200 && xhr.status < 300){
            //处理服务端返回的结果
            result.innerHTML = xhr.response
        }
    }
}
 //加载学生的方法
        function loadStudent(name = '') {
            let xhr = new XMLHttpRequest()
            xhr.open('GET', 'http://localhost:8848/list?name=' + name)
            xhr.send()
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        document.querySelector('#tbody').innerHTML = template('list', JSON.parse(xhr.responseText))
                    }
                }
            }
        }
        //调用加载学生信息的方法
        loadStudent()
        //搜索按钮点事件
        document.querySelector('#search').onclick = function () {
            //重新调用加载学生信息的方法
            loadStudent(document.querySelector('#name').value)
        }
        //添加按钮点击事件
        document.querySelector('#add').onclick = function () {
            //获取用户输入的信息
            let name = document.querySelector('#name2').value
            let sex = '男'
            if (document.querySelector('#nv').checked) {
                sex = '女'
            }
            let age = document.querySelector('#age').value
            let hobbies = []
            document.getElementsByName('hobbies').forEach(r => {
                if (r.checked) {
                    hobbies.push(r.value)
                }
            })
            let email = document.querySelector('#email').value
            let isVIP = document.querySelector('#isVIP').checked
            //根据获取到的信息,创建一个学生对象
            let stu = {
                name, sex, age, hobbies, email, isVIP
            }
            //定义请求的地址
            let url = 'http://localhost:8848/add'
            if(document.querySelector('#add').innerHTML=='修改'){
                //切换成修改接口地址
                url = 'http://localhost:8848/update'
                //设置学生对象的_id属性
                stu._id = document.querySelector('#_id').value
            }
            let xhr = new XMLHttpRequest()
            xhr.open('POST', url)
            //通过请求头设置post请求体的格式是json
            xhr.setRequestHeader('content-type', 'application/json')
            xhr.send(JSON.stringify(stu))
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        if (JSON.parse(xhr.responseText)) {
                            if(document.querySelector('#add').innerHTML=="添加"){
                                alert('添加成功')
                            }else{
                                alert('修改成功')
                                document.querySelector('#add').innerHTML = '添加'
                            }
                            //调用加载学生信息的方法
                            loadStudent()
                            //清空表单
                            clearInput()
                        }
                    }
                }
            }
        }

        //删除方法
        function del(_id) {
            if (!confirm('确定删除吗?')) return
            let xhr = new XMLHttpRequest()
            xhr.open('POST', 'http://localhost:8848/delete')
            //通过请求头设置post请求体的格式是json
            xhr.setRequestHeader('content-type', 'application/json')
            xhr.send(JSON.stringify({ _id }))
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        if (JSON.parse(xhr.responseText)) {
                            alert('删除成功')
                            //调用加载学生信息的方法
                            loadStudent()
                        }
                    }
                }
            }
        }

        //根据id获取学生信息
        function getOne(_id) {
            let xhr = new XMLHttpRequest()
            xhr.open('GET', 'http://localhost:8848/getOne?_id=' + _id)
            xhr.send()
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status === 200) {
                        let stu = JSON.parse(xhr.responseText)
                        document.querySelector('#name2').value = stu.name
                        if(stu.sex=='男'){
                            document.querySelector('#nan').checked = true
                        }else{
                            document.querySelector('#nv').checked = true
                        }
                        document.querySelector('#age').value = stu.age
                        //爱好
                        stu.hobbies.forEach(h=>{
                            document.querySelector(`input[value='${h}']`).checked = true
                        })
                        document.querySelector('#email').value = stu.email
                        document.querySelector('#isVIP').checked = stu.isVIP
                        //将_id在隐藏域里面保存起来
                        document.querySelector('#_id').value = stu._id
                    }
                }
            }
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '修改'
        }

        //取消按钮点击事件
        document.querySelector('#cancel').onclick = function(){
            //清空表单元素
            clearInput()
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '添加'
        }

        //清空表单方法
        function clearInput() {
            document.querySelector('#name2').value = ""
            document.querySelector('#nan').checked = true
            document.querySelector('#age').value = ""
            document.getElementsByName('hobbies').forEach(r => {
                r.checked = false
            })
            document.querySelector('#email').value = ""
            document.querySelector('#isVIP').checked = false
        }

3.3.3 响应 JSON

//发送请求
const xhr = new XMLHttpRequest();
//设置响应体数据的类型
xhr.responseType = 'json';
//初始化
xhr.open('GET','http://127.0.0.1:8000/json-server');
//发送
xhr.send()
//事件绑定
xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
        if(xhr.status >=200 && xhr.status<300){
            // result.innerHTML = xhr.response
            //手动对数据转换
            // let data = JSON.parse(xhr.response)
            // console.log(data);
            // result.innerHTML = data.name
            //自动转换-->设置响应体数据的类型
            // console.log(xhr.response);
            result.innerHTML = xhr.response.name
        }
    }
}

3.3.4 IE缓存问题

const xhr = new XMLHttpRequest();
// url添加时间戳
xhr.open('GET','http://127.0.0.1:8000/ie?t='+Date.now());
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
        if(xhr.status >= 200 && xhr.status < 300){
            result.innerHTML = xhr.response
        }
    }
}

3.3.5 请求超时与网络异常

const xhr = new XMLHttpRequest();
//超时设置 2s 设置
xhr.timeout = 2000
//超时回调
xhr.ontimeout = function(){
    alert('网络异常,请稍后重试!')
}
//网络异常回调
xhr.onerror = function(){
    alert('你的网络似乎出了一些问题!')
}
xhr.open('GET','http://127.0.0.1:8000/delay');
xhr.send();
xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
        if(xhr.status >= 200 && xhr.status < 300){
            result.innerHTML = xhr.response
        }
    }
}

3.3.6 取消请求

let xhr = new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/delay');
//发送请求
xhr.send()
//取消请求
xhr.abort()

3.3.7 重复发送请求问题

//判断标识变量
if(isSending) x.abort();  //如果正在发送,则取消该请求,创建一个新的请求
x = new XMLHttpRequest();
//修改 标识变量的值
isSending = true
x.open('GET', 'http://127.0.0.1:8000/delay');
x.send()
x.onreadystatechange = function(){
    if(x.readyState === 4){
        //修改标识变量
        isSending = false
    }
}

3.4 jQuery AJAX


3.4.1 GET方式

// 第四个参数:设置json。表示响应体是json对象
// 第四个参数:不设置。默认响应体是字符串
$.get('http://127.0.0.1:8000/jquery-server',{a:100,b:200},function(data){
  console.log(data);
},'json')

3.4.2 POST方式

$.post('http://127.0.0.1:8000/jquery-server',{a:100,b:200},function(data){
  console.log(data);
})

3.4.3 通用型方法ajax

$.ajax({
    //url         
    url:'http://127.0.0.1:8000/jquery-server',
    //参数
    data:{a:100,b:200},
    //请求类型
    type:'GET',
    //响应体结果
    dataType:'json',
    //成功的回调
    success:function(data){
        console.log(data);
    },
    //超时时间
    timeout:2000,
    //失败的回调
    error:function(){
        console.log('出错啦!');
    },
    //头信息
    headers:{
        c:300,
        d:400
    }
})
//加载学生的方法
        function loadStudent(name = '') {
            $.get('http://localhost:8848/list', {
                name
            }, r => {
                document.querySelector('#tbody').innerHTML = template('list', r)
            })
        }
        //调用加载学生信息的方法
        loadStudent()
        //搜索按钮点事件
        document.querySelector('#search').onclick = function () {
            //重新调用加载学生信息的方法
            loadStudent(document.querySelector('#name').value)
        }
        //添加按钮点击事件
        document.querySelector('#add').onclick = function () {
            //获取用户输入的信息
            let name = document.querySelector('#name2').value
            let sex = '男'
            if (document.querySelector('#nv').checked) {
                sex = '女'
            }
            let age = document.querySelector('#age').value
            let hobbies = []
            document.getElementsByName('hobbies').forEach(r => {
                if (r.checked) {
                    hobbies.push(r.value)
                }
            })
            let email = document.querySelector('#email').value
            let isVIP = document.querySelector('#isVIP').checked
            //根据获取到的信息,创建一个学生对象
            let stu = {
                name, sex, age, hobbies, email, isVIP
            }
            //定义请求的地址
            let url = 'http://localhost:8848/add'
            if (document.querySelector('#add').innerHTML == '修改') {
                //切换成修改接口地址
                url = 'http://localhost:8848/update'
                //设置学生对象的_id属性
                stu._id = document.querySelector('#_id').value
            }

            //注意:这里添加和修改操作,采用的是jquery的统一ajax方法,因为要做特殊处理
            $.ajax({
                url,
                type: 'POST',
                data: stu,
                dataType: 'json',
                // 这里需要采用传统的方式来序列化数据,jquery默认会将对象的对象属性拆分开了序列化
                traditional: true,
                success: r => {
                    if (r) {
                        if (document.querySelector('#add').innerHTML == "添加") {
                            alert('添加成功')
                        } else {
                            alert('修改成功')
                            document.querySelector('#add').innerHTML = '添加'
                        }
                        //调用加载学生信息的方法
                        loadStudent()
                        //清空表单
                        clearInput()
                    }
                }
            })
        }

        //删除方法
        function del(_id) {
            if (!confirm('确定删除吗?')) return
            $.post('http://localhost:8848/delete', { _id }, r => {
                if (r) {
                    alert('删除成功')
                    //调用加载学生信息的方法
                    loadStudent()
                }
            })
        }

        //根据id获取学生信息
        function getOne(_id) {
            let xhr = new XMLHttpRequest()
            $.get('http://localhost:8848/getOne', { _id }, stu => {
                document.querySelector('#name2').value = stu.name
                if (stu.sex == '男') {
                    document.querySelector('#nan').checked = true
                } else {
                    document.querySelector('#nv').checked = true
                }
                document.querySelector('#age').value = stu.age
                //爱好
                stu.hobbies.forEach(h => {
                    document.querySelector(`input[value='${h}']`).checked = true
                })
                document.querySelector('#email').value = stu.email
                document.querySelector('#isVIP').checked = stu.isVIP
                //将_id在隐藏域里面保存起来
                document.querySelector('#_id').value = stu._id
            })
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '修改'
        }

        //取消按钮点击事件
        document.querySelector('#cancel').onclick = function () {
            //清空表单元素
            clearInput()
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '添加'
        }

        //清空表单方法
        function clearInput() {
            document.querySelector('#name2').value = ""
            document.querySelector('#nan').checked = true
            document.querySelector('#age').value = ""
            document.getElementsByName('hobbies').forEach(r => {
                r.checked = false
            })
            document.querySelector('#email').value = ""
            document.querySelector('#isVIP').checked = false
        }

3.5 axios

3.5.1 GET方式

axios.get('/axios-server',{
    //url 参数
    params:{
        id:100,
        vip:7
    },
    //请求头信息
    headers:{
        name:'张三',
        age:20
    }
}).then(value=>{
    console.log(value);
})

3.5.2 POST方式

axios.post('/axios-server',{
    //请求体
    {
        username:'admin',
        password:'admin'
	},
    {
    //url 参数
    params:{
        id:200,
        vip:9
    },
    //请求头参数
    headers:{
        height:180,
        weight:180
    }
}).then(value=>{
    console.log(value);
})

3.5.3 通用方式

axios({
    //请求方法
    method: 'POST',
    //url
    url:'/axios-server',
    //url参数
    params:{
        vip:10,
        level:30
    },
    //头信息
    headers:{
        a:100,
        b:200
    },
    //请求体参数
    data:{
        username:'admin',
        password:'admin'
    }
}).then(response=>{
    console.log(response);
    //响应状态码
    console.log(response.status);
    //响应状态字符串
    console.log(response.statusText);
    //响应头信息
    console.log(response.headers);
    //响应体
    console.log(response.data);
})
//加载学生的方法
        /* function loadStudent(name = '') {
            //get方法(),第一个参数是请求地址,第二个参数对象设置请求参数
            //注意:请求参数要放置在第二个参数对象的params属性中
            axios.get('http://localhost:8848/list', {
                params: {
                    name
                }
            }).then(({ data }) => {
                document.querySelector('#tbody').innerHTML = template('list', data)
            })
        } */

        async function loadStudent(name = '') {
            //async 配合 await,简化了.then返回结果的过程
            let {data} = await axios.get('http://localhost:8848/list', {
                params: {
                    name
                }
            })
            document.querySelector('#tbody').innerHTML = template('list', data)
        }


        //调用加载学生信息的方法
        loadStudent()
        //搜索按钮点事件
        document.querySelector('#search').onclick = function () {
            //重新调用加载学生信息的方法
            loadStudent(document.querySelector('#name').value)
        }
        //添加按钮点击事件
        document.querySelector('#add').onclick = function () {
            //获取用户输入的信息
            let name = document.querySelector('#name2').value
            let sex = '男'
            if (document.querySelector('#nv').checked) {
                sex = '女'
            }
            let age = document.querySelector('#age').value
            let hobbies = []
            document.getElementsByName('hobbies').forEach(r => {
                if (r.checked) {
                    hobbies.push(r.value)
                }
            })
            let email = document.querySelector('#email').value
            let isVIP = document.querySelector('#isVIP').checked
            //根据获取到的信息,创建一个学生对象
            let stu = {
                name, sex, age, hobbies, email, isVIP
            }
            //定义请求的地址
            let url = 'http://localhost:8848/add'
            if (document.querySelector('#add').innerHTML == '修改') {
                //切换成修改接口地址
                url = 'http://localhost:8848/update'
                //设置学生对象的_id属性
                stu._id = document.querySelector('#_id').value
            }
            axios.post(url, stu).then(({ data }) => {
                if (data) {
                    if (document.querySelector('#add').innerHTML == "添加") {
                        alert('添加成功')
                    } else {
                        alert('修改成功')
                        document.querySelector('#add').innerHTML = '添加'
                    }
                    //调用加载学生信息的方法
                    loadStudent()
                    //清空表单
                    clearInput()
                }
            })
        }

        //删除方法
        function del(_id) {
            if (!confirm('确定删除吗?')) return
            axios.post('http://localhost:8848/delete', { _id }).then(({ data }) => {
                if (data) {
                    alert('删除成功')
                    //调用加载学生信息的方法
                    loadStudent()
                }
            })
        }

        //根据id获取学生信息
        function getOne(_id) {
            axios.get('http://localhost:8848/getOne', {
                params: {
                    _id
                }
            }).then(({data:stu}) => {
                document.querySelector('#name2').value = stu.name
                if (stu.sex == '男') {
                    document.querySelector('#nan').checked = true
                } else {
                    document.querySelector('#nv').checked = true
                }
                document.querySelector('#age').value = stu.age
                //爱好
                stu.hobbies.forEach(h => {
                    document.querySelector(`input[value='${h}']`).checked = true
                })
                document.querySelector('#email').value = stu.email
                document.querySelector('#isVIP').checked = stu.isVIP
                //将_id在隐藏域里面保存起来
                document.querySelector('#_id').value = stu._id
            })
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '修改'
        }

        //取消按钮点击事件
        document.querySelector('#cancel').onclick = function () {
            //清空表单元素
            clearInput()
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '添加'
        }

        //清空表单方法
        function clearInput() {
            document.querySelector('#name2').value = ""
            document.querySelector('#nan').checked = true
            document.querySelector('#age').value = ""
            document.getElementsByName('hobbies').forEach(r => {
                r.checked = false
            })
            document.querySelector('#email').value = ""
            document.querySelector('#isVIP').checked = false
        }

3.6 fetch

fetch('http://127.0.0.1:8000/fetch-server?vip=10',{
    //请求方法
    method:'POST',
    //请求头
    headers:{
        name:'bing'
    },
    //请求体
    body:'username=admin&password=admin'
}).then(response=>{
    // console.log(response);
    // return response.text()
    return response.json()
}).then(response=>{
    console.log(response);
})
//加载学生的方法
        function loadStudent(name = '') {
            //fetch()方法,用于发送请求,返回结果是响应对象
            fetch('http://localhost:8848/list?name=' + name).then(res => {
                //响应对象的json()方法,返回请求的结果
                return res.json()
            }).then(r => {
                document.querySelector('#tbody').innerHTML = template('list', r)
            })
        }
        //调用加载学生信息的方法
        loadStudent()
        //搜索按钮点事件
        document.querySelector('#search').onclick = function () {
            //重新调用加载学生信息的方法
            loadStudent(document.querySelector('#name').value)
        }
        //添加按钮点击事件
        document.querySelector('#add').onclick = function () {
            //获取用户输入的信息
            let name = document.querySelector('#name2').value
            let sex = '男'
            if (document.querySelector('#nv').checked) {
                sex = '女'
            }
            let age = document.querySelector('#age').value
            let hobbies = []
            document.getElementsByName('hobbies').forEach(r => {
                if (r.checked) {
                    hobbies.push(r.value)
                }
            })
            let email = document.querySelector('#email').value
            let isVIP = document.querySelector('#isVIP').checked
            //根据获取到的信息,创建一个学生对象
            let stu = {
                name, sex, age, hobbies, email, isVIP
            }

            //定义请求的地址
            let url = 'http://localhost:8848/add'
            if (document.querySelector('#add').innerHTML == '修改') {
                //切换成修改接口地址
                url = 'http://localhost:8848/update'
                //设置学生对象的_id属性
                stu._id = document.querySelector('#_id').value
            }
            //fetch()方法的第一个参数是请求地址
            //第二个参数是配置对象
            fetch(url, {
                //请求方式是POST
                method: 'POST',
                //设置请求头信息
                headers: {
                    'Content-Type': 'application/json',
                },
                //设置post请求方式的请求体,其实就是post请求参数
                body: JSON.stringify(stu)
            }).then(res => {
                return res.json()
            }).then(r => {
                if (r) {
                    if (document.querySelector('#add').innerHTML == "添加") {
                        alert('添加成功')
                    } else {
                        alert('修改成功')
                        document.querySelector('#add').innerHTML = '添加'
                    }
                    //调用加载学生信息的方法
                    loadStudent()
                    //清空表单
                    clearInput()
                }
            })
        }

        //删除方法
        function del(_id) {
            if (!confirm('确定删除吗?')) return
            fetch('http://localhost:8848/delete', {
                //请求方式是POST
                method: 'POST',
                //设置请求头信息
                headers: {
                    'Content-Type': 'application/json',
                },
                //设置post请求方式的请求体,其实就是post请求参数
                body: JSON.stringify({ _id })
            }).then(res => {
                return res.json()
            }).then(r => {
                if (r) {
                    alert('删除成功')
                    //调用加载学生信息的方法
                    loadStudent()
                }
            })
        }

        //根据id获取学生信息
        function getOne(_id) {
            fetch('http://localhost:8848/getOne?_id=' + _id).then(res => {
                return res.json()
            }).then(stu => {
                document.querySelector('#name2').value = stu.name
                if (stu.sex == '男') {
                    document.querySelector('#nan').checked = true
                } else {
                    document.querySelector('#nv').checked = true
                }
                document.querySelector('#age').value = stu.age
                //爱好
                stu.hobbies.forEach(h => {
                    document.querySelector(`input[value='${h}']`).checked = true
                })
                document.querySelector('#email').value = stu.email
                document.querySelector('#isVIP').checked = stu.isVIP
                //将_id在隐藏域里面保存起来
                document.querySelector('#_id').value = stu._id
            })

            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '修改'
        }

        //取消按钮点击事件
        document.querySelector('#cancel').onclick = function () {
            //清空表单元素
            clearInput()
            //修改添加按钮的文本
            document.querySelector('#add').innerHTML = '添加'
        }

        //清空表单方法
        function clearInput() {
            document.querySelector('#name2').value = ""
            document.querySelector('#nan').checked = true
            document.querySelector('#age').value = ""
            document.getElementsByName('hobbies').forEach(r => {
                r.checked = false
            })
            document.querySelector('#email').value = ""
            document.querySelector('#isVIP').checked = false
        }

你可能感兴趣的:(前端,数据库,mongodb,ajax,前端,node.js)