前端常用的跨域方案
目录
[TOC]
前言
发送请求XMLHttpRequest(ajax, $ajax, axois),fetch
file:///F://vue阶段/vue工程化/_systerm/public/index.html:file协议不允许发送ajax请求
平时项目中,同源请求需求很少,服务器部署的时候是分开的(web服务器,数据服务器),调用第三方平台接口,本地开发的时候,在自己电脑上预览项目,而数据接口是请求其他服务器的
开发的时候跨域,项目部署的时候,是部署到同一台服务器上的同一个服务下(生产同源)
前后端不分离的项目,开发的时候本地也会把后台服务启动,所以开发也是同源,部署也是同源
全栈开发,基于SSR渲染(js+nodejs)这也是同源的
跨域
浏览器有安全策略限制,默认情况下是不允跨域请求的(web页面地址vs请求接口地址 协议,域名,端口号,三者有一个不一致就是跨域)
解决跨域方案
一.修改本地HOST:
开发的时候是跨域的,但是部署的时候是同源的,我们只要解决开发跨域问题即可
- DNS解析-->找本地的DNS缓存记录(本地host文件中查找)
- 客户端浏览器地址栏输入www.baidu.com
- host配置:www.baidu.com:80 127.0.0.1:80
这样保证饿了浏览器是www.baidu.com但是访问的是本地开发的这个项目,在这个基础上我们去www.baidu.com/user/list发请求,相当于欺骗了浏览器,让浏览器认为我是同源的
二.JSONP
script标签的src请求资源文件(基于GET请求方式)他是不存在跨域限制
JSONP的原理就是利用了这个机制,
只能是GET请求,服务器必须服务器支持
创建一个全局函数 把函数通过问号传参方式发送给服务器
代码
<script>
(function () {
window['fn'] = function fn(result) {
console.log(result);
};
})();
</script>
<script src="https://www.baidu.com/sugrec?prod=pc&wd=周冬雨&cb=fn"></script>
封装jsonp
基于promise管理封装jsonp
- 1.初始化参数,不传 默认:params=null, 函数名为callback
- 2.创建全局函数
- 3.处理url:把参数函数名,基于问号参数形式,拼接到url末尾
- 4.发送请求:创建script标签插入到页面中
(function () {
// 检测是否为纯粹对象
const isPlainObject = function isPlainObject(obj) {
let proto, Ctor;
if (!obj || Object.prototype.toString.call(obj) !== "[object Object]") return false;
proto = Object.getPrototypeOf(obj);
if (!proto) return true;
Ctor = proto.hasOwnProperty('constructor') && proto.constructor;
return typeof Ctor === "function" && Ctor === Object;
};
// 把普通对象变为URLENCODED格式字符串
const stringify = function stringify(obj) {
let str = ``,
keys = Object.keys(obj).concat(Object.getOwnPropertySymbols(obj));
keys.forEach(key => {
str += `&${key}=${obj[key]}`;
});
return str.substring(1);
};
/* 封装JSONP函数 */
const jsonp = function jsonp(url, config) {
return new Promise((resolve, reject) => {
// 初始化参数
if (typeof url !== "string") throw new TypeError('url is not a string!');
if (!isPlainObject(config)) config = {};
config = Object.assign({
params: null,
jsonp: 'callback'
}, config);
// 创建一个全局函数
let f_name = `jsonp${+new Date()}`;
window[f_name] = value => {
// 请求成功
resolve(value);
delete window[f_name];
document.body.removeChild(script);
};
// 处理URL「拼接问号参数 & 拼接函数名」
let params = config.params;
if (params) {
if (isPlainObject(params)) params = stringify(params);
url += `${url.includes('?')?'&':'?'}${params}`;
}
//拼接函数
url += `${url.includes('?')?'&':'?'}${config.jsonp}=${f_name}`;
// 发送请求
let script = document.createElement('script');
script.src = url;
script.onerror = err => {
// 请求失败
reject(err);
};
document.body.appendChild(script);
});
};
/* 暴露API */
if (typeof module === "object" && typeof module.exports === "object") module.exports = jsonp;
if (typeof window !== "undefined") window.jsonp = jsonp;
})();
调用
<script>
jsonp('https://www.baidu.com/sugrec', {
//问号传参值&&关键词
params: {
prod: 'pc',
wd: '周冬雨'
},
jsonp: 'cb'//默认传递的函数名callback
}).then(value => {
console.log(value);
});
</script>
三.CORS
CORS跨域资源共享:只要服务器端设置允许源即可,允许客户端发送请求,这样就可以忽略浏览器的安全策略, ,客户端不用做什么,最多配置一个允许携带资源凭证 withCredentials: true
- 服务器设置Access-Control-Allow-Origin",
- 设置为*:允许所有原访问(不安全),不允许携带资源凭证(例如cooike)Access-Control-Allow-Credentials", 必须为false
- 不设置*号,只能设置单一源,但是可以携带资源凭证
- 客户端向服务器发请求一般都有orgin 和referer 记录客户端的 协议,域名,端口号,服务器根据字段设置白名单
四 proxy
proxy跨域代理:利用后端和后端的通信默认没有安全策略限制的
中间代理服务器,预览web页面,帮助我们从其他服务器获取资源
开发环境node.js自己写, vue react==>webpack-dev-server
生成环境下nginx反向代理
代码
devServer: {
proxy: {
'/': {
target: 'http://127.0.0.1:9999',
changeOrigin: true
}
}
}
