一 跨域问题的产生及其价值意义
真实项目的开发中
一个项目部署在不同服务器上
web服务器:静态资源 kbs.game.qq.com
data服务器: api.sports.qq.com
图片服务器
- 协议
- 域名
- 端口号
三者一致是同源,只要有一个不同就是跨域
eg:
web服务器地址:http://127.0.0.1:3000/index.html
数据接口地址:http://127.0.0.1:4000/list
二 JSONP跨域解决方案的底层原理
- script
- img
- link
- iframe
不存在跨域请求的限制
前端代码:
- 动态创建script标签
- 设置src跨域地址,注意此时的回调函数也一同传到服务器
- script标签添加之页面
<script>
$("button").click(function(){
var script=document.createElement("script");
script.src=`http://localhost:3000?callback=show`;
document.body.appendChild(script);
})
function show(weather){ //回调函数
alert(weather);
//document.write(weather);
//回调函数结尾删除标签。
$("body>script:last").remove(); //为了节省内存每次移除创建的标签
}
</script>
后端处理代码
var express = require("express");
//var app = express();
//映入支持接收的请求,如何接收callback
const http = require("http");
const url = require("url");
var weather = "宝鸡 晴 18-32";
http.createServer(
(req, res) => {
//对请求进行处理
var urls = url.parse(req.url, true);
var callback = urls.query.callback;
res.writeHead(200, {
"Content-Type": "text/plain; charset=utf-8"
});
res.write(`${callback}("${weather}")`);
res.end();
}
).listen(3000, () => {
console.log("Server is start!");
});
缺点:JSONP只能处理GET请求
url劫持数据不安全,安全性低下
需要前后端一起处理
CORS跨域资源共享
服务器设置请求文件
Access-Control-Allow-Origin
- 客户端发送(ajax/fetch)
- 服务端设置相关的信息()
options:试探性请求
- 简单请求 复杂请求请参考—>https://www.jianshu.com/p/37c248258e89
非简单请求参考https://www.jianshu.com/p/ebd498cc3c52 - 服务端配置如下
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://localhost:8000");
//=》* (支持多源,就不能允许携带cookies了)
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
if (req.method === 'OPTIONS') { res.send('OK!'); return; }
next(); });
//客户端发送请求代码
axios.defaults.baseURL = 'http://127.0.0.1:8888';
axios.defaults.withCredentials = true;
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = function (data) {
if (!data) return data;
let result = ``;
for (let attr in data) {
if (!data.hasOwnProperty(attr)) break;
result += &${attr}=${data[attr]}; }
return result.substring(1); };
axios.interceptors.response.use(function onFulfilled(response) {
return response.data; },
function onRejected(reason) {
return Promise.reject(reason);
});
axios.defaults.validateStatus = function (status) {
return /^(2|3)\d{2}$/.test(status);
}
缺点:多源性和携带cookies不能共存
基于http proxy实现跨域请求
- 客户端配置
webpack webpack -dev- server
devServer:{
port: 3000,
progress:true,
contentBase:'./build',
proxy:{
'/':{
target:'http://127.0.0.1:3001',//将目标地址改为http://127.0.0.1:3001
changeOrigin:true
}
}
}
注意:vue react框架开发的项目适用
基于 post message实现跨域处理
// A页面向B页面发送请求
<iframe src="http://127.0.0.1:1002/MESSAGE/B.html"></iframe>
<script>
let iframe = document.querySelector('iframe');
iframe.onload = function () {
iframe.contentWindow.postMessage('hhhh', '"http://127.0.0.1:1002/MESSAGE/B.html');//发送请求给B
}
window.onmessage = function (ev) {
console.log(ev.data);
}
</script>
//B页面
<script>
window.onmessage = function (ev) {
console.log(ev.data);
ev.source.postMessage(ev.data+'@@', ev.origin); //发送给A
}
</script>
web scoket
- web scoket协议跨域 scoket io
//前端处理
<script src="./socket.io.js"></script>
<script>
let socket = io('http://127.0.0.1:3001/');
//=>连接成功处理
socket.on('connect', function() {
//=>监听服务端消息
socket.on('message', function(msg) {
console.log('data from server:' + msg);
});
//=>监听服务端关闭
socket.on('disconnect', function() {
console.log('server socket has closed!');
});
});
//=>发送消息给服务器端
socket.send("zhufengpeixun");
</script>
//服务器端处理
//=>监听socket连接:server是服务器创建的服务
socket.listen(server).on('connection', function(client) {
//=>接收信息
client.on('message', function(msg) {
//=>msg客户端传递的信息
//...
client.send(msg+'@@');
});
//=>断开处理
client.on('disconnect', function() {
console.log('client socket has closed!');
});
});
nginx反向代理
- nginx反向代理 服务器进行部署,前端不需要干什么 服务器请求不存在跨域
- 例:www.zhufengpeixun.cn -> www.zhufengpeixun.com
#proxy服务器
server {
listen 80;
server_name www.zhufengpeixun.com;
location / {
proxy_pass www.zhufengpeixun.cn; #反向代理
proxy_cookie_demo www.zhufengpeixun.cn www.zhufengpeixun.com;
add_header Access-Control-Allow-Origin www.zhufengpeixun.cn;
add_header Access-Control-Allow-Credentials true;
}
}
基于iframe的跨域解决方案
- document.domin 只能实现同一个主域不同子域之间的操作
v.qq.com —》 sprots.qq.com
<iframe src="http://school.zhufengpeixun.cn/B.html"></iframe>
<script>
document.domain = 'zhufengpeixun.cn';
var user = 'admin';
</script>
//子页面B http://school.zhufengpeixun.cn/B.html
<script>
document.domain = 'zhufengpeixun.cn';
alert(window.parent.user);
</script>
- window.name+iframe
必须有三个页面 - location.hash +iframe
from 珠峰跨域公开课总结,持续更新中