一、跨域
-
1、什么是跨域
- 请求所在的服务器, 与要被请求的服务器
- 两个服务器地址
- 协议: http/https
- 域名: localhost/www.baidu.com/www.juejin.…
- 端口号: 0~65535
- 上述的三个, 有一个不同, 就会触发跨域, 上边的就是我们浏览器的同源策略,只要违反了同源策略一定会触发跨域
-
2、跨域会导致什么情况的发生
- 请求能够正常的发送成功
- 服务器也一定能够正常的响应成功
- 但是浏览器会认为 当前的请求不安全, 然后将本次请求的信息拦截掉,所以最终的结果是:
- 前端能够正常的发出去请求
- 服务端能够正常的响应回数据
- 但是前端不能正常的接收到数据, 因为被浏览器拦截了
二、解决跨域的三种方式
-
- jsonp
-
- cors
-
- proxy 服务器代理
1、方法一jsonp
1)server-api/index.js
const express = require("express");
const bodyParser = require("body-parser");
// 创建服务器
const server = express();
server.use(bodyParser.urlencoded({ extended: false }));
server.use(bodyParser.json());
// 配置接口处理
server.get("/api/a", (req, res) => {
// console.log('如果我打印了, 说明有人请求我了, 然后我一定会返回一个数据')
// res.send({
// code: 1,
// msg: "请求 a 成功",
// });
// res.send('console.log(10086)')
// res.send('fn(100)')
// res.send('fn(10086)')
// res.send('fn({code: 1, msg: "请求 a 成功"})')
// const data = {
// code: 1,
// msg: "请求 a 成功",
// };
// // res.send(`fn(${data})`); // 不允许这样传递
// res.send(`fn(${JSON.stringify(data)})`); // ????
const { callback } = req.query;
const data = {
code: 1,
msg: "请求 a 成功",
};
res.send(`${callback}(${JSON.stringify(data)})`);
});
server.post("/api/b", (req, res) => {
res.send({
code: 1,
msg: "请求 b 成功",
});
// res.send('console.log(10010)')
});
// 配置端口号
server.listen(8081, () => console.log("8081 接口服务器启动成功"));
2)server-static
1.server-static/index.js
const express = require("express");
// 创建服务器
const server = express();
// 配置静态资源
server.use("/static", express.static("./client"));
// 配置端口号
server.listen(8080, () => console.log("8080 静态页面服务器启动成功"));
2.client/index.js
console.log("index.html 引入 index.js 成功");
getA()
function getA () {
const xhr = new XMLHttpRequest()
xhr.open('get', 'http://localhost:8081/api/a')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
}
3.client/index.html
- 文件的名字是为了让用户知道这个文件是什么,文件的后缀(.js .css .html)是为了让一些软件认识这个文件
- script 的 src 属性会将地址中的文件内容读取一遍,然后将文件内容当成 JS 代码执行一遍
- 目前我们的这个写法其实就是利用了jsonp解决了跨域
- 因为同源策略是浏览器用来限制 ajax 的,script 标签 的 src 属性, 不会收到限制, 所以可以跳出同源策略,但是当前的解决方案也不是特别完美, 因为目前的 jsonp 只能处理 get 方式的跨域, post 方式的无法解决
<script>
function num123(data) {
console.log('数据: ', data)
}
</script>
<script src="http://localhost:8081/api/a?callback=num123"></script>
<!--
当前我们已经成功实现 jsonp 处理跨域, 并且拿到了 后端返回的数据
但是有一些问题
函数名 一定是 fn 吗?
我们目前没有办法确保, 函数名一定是 fn
-->
<!-- <script>
function fn(data) {
console.log('数据: ', data)
}
</script> -->
<!--
当前会像 http://localhost:8081/api/a 发送一个 get 请求
这个接口会返回一个字符串: fn()
然后这个标签会将这个字符串当成一个 js 代码执行一遍
-->
<!-- <script src="http://localhost:8081/api/a"></script> -->
<!--
当前页面执行的时候, 会引入一个 在线的 JS
但是这个地址最终返回的数据不是一个 JS 文件
而是一个字符串: console.log(10086)
然后当前标签会把这个字符串当成一个 JS 代码执行一遍
-->
2、方法二、cors
- 刚才我们使用 jsonp 完成了一个 get 方式的跨域处理,但是如果我们遇到了 post 方式, 我们无法利用 jsonp 完成跨域处理
- 利用一个 新的方式 cors 解决跨域
- 出现跨域的流程:
-
- 前端发送请求 (发送成功)
-
- 后端反馈响应 (反馈成功)
-
- 浏览器解析后端反馈的数据 (此时发现当前的请求违反了 同源策略, 所以触发了跨域, 将后端反馈的数据浏览器拦截掉)
-
- 现在前端没有办法正常的接收到后端的数据
-
- cors 解决跨域的思路
-
- 前端发送请求 (发送成功)
-
- 后端反馈响应 (反馈成功) 但是再反馈的时候告诉浏览器我们这次通讯是合法的, 请不要拦截
-
- 浏览器解析后端反馈的数据 (此时发现了当前的请求违反了 同源策略, 但是后端告诉我们当前的请求时合法的, 所以不触发跨域, 正常给前端反馈数据)
-
- 前端此时正常接收到数据了
-
1)server-api/index.js
3、方法三、proxy 服务器代理
1)server-static/client/index.js
console.log("index.html 引入 index.js 成功");
getA()
function getA () {
const xhr = new XMLHttpRequest()
// xhr.open('get', 'http://localhost:8081/api/a')
xhr.open('get', 'http://localhost:8080/api/mya')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
}
getB()
function getB () {
const xhr = new XMLHttpRequest()
xhr.open('post', 'http://localhost:8080/api/myb')
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
}
2)server-static/index.js
const express = require("express");
const axios = require("axios");
// 创建服务器
const server = express();
// 配置静态资源
server.use("/static", express.static("./client"));
server.get("/api/mya", (req, res) => {
// 当我们这个接口触发, 是我们自己的页面发了一个请求, 我们需要向 8081 这个服务器 的 /api/a 这个接口发一个请求
// axios({
// method: 'GET',
// url: 'http://localhost:8081/api/a'
// }).then((data) => {
// res.send(data.data);
// })
axios({
method: "GET",
url: "http://localhost:8081/api/a",
}).then(({ data }) => {
res.send(data);
});
});
server.post("/api/myb", async (req, res) => {
// 当我们这个接口触发, 是我们自己的页面发了一个请求, 我们需要向 8081 这个服务器 的 /api/a 这个接口发一个请求
const { data } = await axios({
method: "POST",
url: "http://localhost:8081/api/b",
});
res.send(data);
});
// 配置端口号
server.listen(8080, () => console.log("8080 静态页面服务器启动成功"));
3)server-api/index.js
const express = require("express");
const bodyParser = require("body-parser");
// 创建服务器
const server = express();
server.use(bodyParser.urlencoded({ extended: false }));
server.use(bodyParser.json());
// 配置接口处理
server.get("/api/a", (req, res) => {
res.send({
code: 1,
msg: "请求 a 成功",
});
});
server.post("/api/b", (req, res) => {
res.send({
code: 1,
msg: "请求 b 成功",
});
});
// 配置端口号
server.listen(8081, () => console.log("8081 接口服务器启动成功"));