- express:设计接口特别方便
let express = require("express");
let app = express();
app.listen(3000, () => console.log("启动成功, http://localhost:3000"));
// 设计接口:每个接口都是单独设计
// 获取POST参数:
// 设置中间件:app.use(express.urlencoded({ extended: false }));
// req.body 请求体
// 获取动态URL地址参数
// 后台设计:/xxx/xxx/xxx/:参数名
// 前端: /xxx/xxx/xxx/值
// req.params.参数名
// 获取get参数
// 前端:URL地址后面 查询字符串
// req.query
- 接口:路由;一级路由 二级路由的设计:提高访问接口的性能!
// 主JS文件
let loginRouter = require('./routers/login.js');
app.use('/api', loginRouter); // 设计一级路由 ,后面引入细分二级路由;
// 细分二级路由文件: 习惯routers文件
const express = require('express');
const router = express.Router();
router.get("/xxx",function(req,res){
});
module.exports = router;
-
中间件:在进入处理响应数据函数直接 一些函数;
- 当要求所有接口都有什么功能的时候,在这些接口之前,设置中间件
app.use(function(req,res,next){req,res每次请求的请求对象和响应对象 next()})
跨域
同源
- IP:服务器,性能特别好电脑 【一个房子】
- 服务器上放在:项目文件夹 / 前端写的页面 && 后台写代码文件;
- 启动:启动服务器一个端口;服务器上很多端口0-65535
- 情形:
- A公司:
- 自己服务器上某个端口下 ,部署了一些代码。
- 代码包括前端代码和后台,都在同一个地方,同一个服务器,同一个端口;
- 前端 代码里:肯定写ajax的一些后台的url接口地址;
- B公司:
- B公司前端开发人员,可以打开A公司发布的域名地址;
- B公司前端开发人员,就可以看到 A公司前端页面内的 接口地址
- 复制 A公司前端页面内的 接口地址,可以放在 B公司 前端页面内;
- 可以获取A公司的数据么?不可以! 同源策略
- A公司:
- 同源策略:
- 是浏览器提供的一种安全机制,限制来自不同源的数据。如果当前页面的URL地址和Ajax的请求地址不同源,浏览器不允许得到服务器的数据;
- 同源:
协议http||https、 IP 和 端口
都相同则同源,只要有一项不同就是不同源;
- 跨域:当前显示的页面中,如果触发了一个Ajax请求,如果请求的URL地址和当前页面的URL地址不同源就是跨域;浏览器不允许跨域获取数据,但是实际开发会经常有这个跨域技术;
- XHR 获取数据资源
- 获取文件资源 JSONP
- 解决:
- jsonp : 需要前端和后端的配合才可以
dataType:"JSONP",
动态创建script 设置src 告诉给后台我们前端有个函数名
返回的文件资源:JS代码 函数名(需要数据)
- cors : 纯粹的后端技术;如果后端实现了cors配置,那么 前端就可以直接跨域获取对应的数据
ajax Day01: 图书管理其实就是后台允许跨域,配置cors
- webpack : 前端工程化构建工具
- css:兼容 自动给生成新的css文件内 兼容性处理
- 前端代码会压缩,里面变量:没有语义化 abcde... 混淆
- 配置项(学会如何配置)
- 代理:配置项 测试开发过程;
cors
- 由于XHR对象被W3C标准化之后,提出了很多XHR Level2的新构想,其中新增了很多新方法(onload、response....)和CORS跨域资源共享。浏览器升级后开始支持CORS方案。
- CORS才是解决跨域的真正解决方案。
- 代码:
- 前端:正常请求;
- 后台:设置响应头;req res 告诉浏览器 允许你拿到数据;
// ---------------------------------前端代码
$.ajax({
url: 'http://localhost:3006/api/cors',
success: function (res) {
console.log(res)
}
});
// ---------------------------------后台代码
const express = require('express');
const app = express();
app.listen(3006, () => console.log('启动了'));
// 测试接口(测试cors)
app.get('/api/cors', (req, res) => {
// 任何请求来源都可以获取响应的数据
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('hi,你看到我了');
});
- 如果所有的url接口都要求允许跨域:
app.get('/api/cors/a', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('hi,你看到我了');
});
app.get('/api/cors/b', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.send('hi,你看到我了');
});
...
// --------------------------改完我们中间件
app.use((req, res,next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
});
app.get('/api/cors/a', (req, res) => {
res.send('hi,你看到我了');
});
app.get('/api/cors/b', (req, res) => {
res.send('hi,你看到我了');
});
- 或者采用第三方模块,作为中间件使用:cors
// npm i cors
const cors = require("cors");
app.use(cors()); // 相当于是上面的封装,当然人家这个更加优化
JSONP
-
JSONP:本质上不是解决跨域,绕过同源跨域,使用的另外一个方式去实现获取数据!
-
实现原理:利用 script 标签的 src 属性,去请求一个接口,因为src属性不受跨域影响。返回一句函数执行;函数执行传入的实参就是后台返回的数据;
-
代码:
- 前端:JSONP方式请求
- 后台:设置专门的代码
// ---------------------------------------前端代码
$.ajax({
dataType: 'jsonp', // 指定该项,表示发送JSONP请求
url: 'http://localhost:3006/api/jsonp',
success: function(res) {
console.log(res)
},
});
// ----------------------------------------测试接口(测试jsonp)
app.get('/api/jsonp', (req, res) => {
// 接收请求的url中的参数
// let fn = req.query.callback;
// res.send(fn + '({ status: 0, message: "登录成功" })');
res.jsonp({ status: 0, message: '登录失败!!!' });
})
ES6:Promise
- ES6语法:语法!语法糖!
回调黑洞
- 需求:有 a.txt、b.txt、c.txt三个文件,使用fs模块按照顺序来依次读取里面的内容并打印:
// 将读取的a、b、c里面的内容,按照顺序输出
const fs = require('fs');
// 读取a文件
fs.readFile('./a.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data.length);
// 读取b文件
fs.readFile('./b.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
// 读取c文件
fs.readFile('./c.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
});
});
- 从上面代码可以看出,回调函数内部嵌套另外的异步请求后的回调函数,代码在表现上较为复杂不易维护,为回调黑洞;
基本使用
- 语法糖
- ES6的语法:注意是JS的核心语法,不是node运行环境所有,也是和 {} []一样,前后端都是可以使用的!
- Promise是什么:构造函数;直译【承诺】
- 意义:解决回调黑洞的问题,以更为合适的方式写异步代码,目标是更加容易维护代码;
- 写还是异步代码;
- 形式:发生改变,看起来更加舒服!更加好维护!
- 1.对异步的代码进行包装,设置【承诺】
// 实例化一个Promise;
// 1.函数作为参数,
// 2.而该函数又有两个形参,
let p = new Promise((resolve, reject) => {
// 形参resolve,单词意思是 完成
// 形参reject ,单词意思是 失败
fs.readFile('./a.txt', 'utf-8', (err, data) => {
if (err) {
// 失败,就告诉别人,承诺失败了
reject(err);
} else {
// 成功,就告诉别人,承诺实现了
resolve(data.length);
}
});
});
- 2.调用:兑现
// 通过调用 p 的then方法,可以获取到上述 “承诺” 的结果
p.then(res => {
console.log(res)
return promis
})
.catch(err => {
console.log(err)
})
- 文件读取的改造:
const fs = require('fs');
// 1. 定义一个承诺
let p = new Promise((resolve, reject) => {
// resolve -- 解决,完成了; 是一个函数
// reject -- 拒绝,失败了; 是一个函数
// 异步操作的代码,它就是一个承诺
fs.readFile('./a.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.length);
}
});
});
// 2. 兑现承诺
p.then((data) => {
console.log(data);
});
- 前一个then里面返回的Promise对象,并且调用resolve的时候传递了数据,数据会被下一个then接收到
const fs = require('fs');
// 1. 定义一个承诺
let a_read = new Promise((resolve, reject) => {
fs.readFile('./a.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.length);
}
});
});
let b_read = new Promise((resolve, reject) => {
fs.readFile('./b.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.length);
}
});
});
let c_read = new Promise((resolve, reject) => {
fs.readFile('./c.txt', 'utf-8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.length);
}
});
});
// 2.调用
a_read
.then((data) => {
console.log(data); // a的数据
return b_read;
})
.then((data) => {
console.log(data); // b的数据
return c_read;
})
.((data) => {
console.log(data); // c的数据
});
优化封装
function read(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
err ? reject(err) : resolve(data.length);
})
});
}
//-----------------------------------------形式1
let a_read = read('./a.txt')
let b_read = read('./b.txt')
let c_read = read('./c.txt')
// 2.调用
a_read
.then((data) => {
console.log(data); // a的数据
return b_read;
})
.then((data) => {
console.log(data); // b的数据
return c_read;
})
.then((data) => {
console.log(data); // c的数据
});
//-----------------------------------------形式2
read('./a.txt')
.then((data) => {
console.log(data); // a的数据
return read('./b.txt');
})
.then((data) => {
console.log(data); // b的数据
return read('./c.txt');
})
.then((data) => {
console.log(data); // c的数据
});
错误获取
// 统一的获取
A.then(function(data) {
console.log(data);
return B;
})
.then(function(data) {
console.log(data);
return C;
})
.then(function(data) {
console.log(data);
})
.catch(function(err) {
console.log(err);
})
ES7:async/await
关键字
-
async 和 await 是 ES2017 中提出来的。
-
异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图解决这个问题。从最早的回调函数,到 Promise 对象,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。
-
不就是读取一个文件吗,干嘛要搞得这么复杂?async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案;
-
ES2017提供了async和await关键字:
- async 用于修饰一个 function,表示该函数里面有异步代码执行操作(Promise的调用)
- await 需要定义在async修饰函数的内部,await后面跟的一般都是一个函数的调用 (函数里面包含有Promise) 【await后面:promise实例化对象】
- 如果有哪一个await操作出错了,会中断async函数的执行
使用
const fs = require('fs');
// 将异步读取文件的代码封装
function myReadFile (path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
err ? reject(err) : resolve(data.length);
});
});
}
// 1.async后的函数表示里面有异步操作
async function abc () {
// 2.等待这个异步操作返回结果!我们现在写的异步,但是完全是同步的方式写异步!!
let a = await myReadFile('./a.txt');
let b = await myReadFile('./b.txt');
let c = await myReadFile('./c.txt');
console.log(b);
console.log(a);
console.log(c);
}
abc();
- await 只会等待 promise 成功的结果, 如果失败了会报错, 需要 try catch
async function abc () {
try {
let a = await myReadFile('./a.txt');
let b = await myReadFile('./b.txt');
let c = await myReadFile('./c.txt');
console.log(b);
console.log(a);
console.log(c);
}
catch (err) {
console.log('读取文件失败了', err)
}
}