一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
说实话,当初为了这个跨域问题,各种博客文章都看过,千篇一律,大部分都是抄来抄去,没有一个能彻底解决问题的。uniapp官方的问答社区,只能呵呵,官方文档都写不明白,更别说找到正确的解决办法了,只能一点点摸索。
为什么会出现跨域问题以及相关机制等,这里就不说了,只重点说一下:跨域场景和解决办法!
本地环境调试 跨域解决办法
跨域场景
- 对于前后端分离的项目,在开发阶段,在本地调试,前端想调用后端的api,那就涉及到跨域
如果前后端项目都在本机localhost下运行,那就不涉及跨域,但是既然分离了,一般前后端也不是一个人写了
- 前端项目调用公共的api接口
后话:这种情况,在部署时,项目肯定不可能和公共api部署在同域服务器,也不可能同域名了,那就必须要解决如何跨域问题
解决办法
jsonp(json padding)
简单说一下原理:
利用script标签没有跨域限制的漏洞,骗浏览器这货的小伎俩...所以并不上什么高大上的新技能,只能说钻了一个空子
方法局限性:
只能处理GET请求,POST/PUT/DELETE等请求则不行!
为了更好的在项目里使用,这里封装一个公共方法,其他地方直接调用即可
'webjsonp': (url, data) => {
return new Promise((resolve, reject) => {
let dataString = url.indexOf('?') === -1 ? '?' : '&'
let callbackName = `jsonpCB_${ Date.now() }`;
url += `${ dataString }callback=${ callbackName }`
if(data) {
for(let k in data) {
url += `&${ k }=${ data[k] }`
}
}
let scriptNode = document.createElement('script');
scriptNode.src = url;
window[callbackName] = (result) => {
result ? resolve(result) : reject('没有返回数据');
delete window[callbackName];
document.body.removeChild(scriptNode);
}
scriptNode.addEventListener('error', () => {
reject('接口返回数据失败');
delete window[callbackName];
document.body.removeChild(scriptNode);
}, false)
document.body.appendChild(scriptNode)
})
}
其实就是创建一个script标签,然后把请求url塞到src属性里,利用Promise,最终将数据返回的一个过程
简单使用
webjsonp('https://apis.xx.yy.com/ws/location/v1/ip', {
key: 'ABCDE-IIJ7P-SAHT3-QDBSK-11222',
output: 'jsonp',
}).then(res => {
// console.log(res);
//....
}).catch(e => {
console.log("error:", e);
});
如果你不想自己封装或者直接使用jsonp也是可以的
再或者直接使用第三方插件也可以,比如 vue-jsonp,这里就过多介绍,怎么个用法的文章一搜一大把
配置manifest.json文件(Proxy代理)
打开该配置文件(源码视图)
找到
"h5"模块,添加如下代码
"h5" : {
"devServer" : {
"proxy" : {
"/api233" : {
"target" : "http://api.xxx.com",
"changeOrigin" : true, //是否跨域
"secure" : false, // 设置支持https协议的代理
"pathRewrite" : {
"^/api233" : "" //这里一定要留空,不然有问题
}
},
"api244": {
"target" : "http://api.yyy.com",
"changeOrigin" : true,
"secure" : false,
"pathRewrite" : {
"^/api244" : ""
}
}//可添加多个...
}
}
}
使用方法
uni.request({
url: '/api233/xx/super_search',
data: {
apikey: "xxxx",
has_coupon: "true",
sort: "desc"
},
method: 'POST',
success(res) {
console.log("success", res);
},
fail(res) {
console.log("err", res);
},
complete() {
that.isLoading = false;
}
});
无论请求是GET还是POST等,都不受限制了
这里的/api233相当于被配置文件中target的值替换掉了,差不多相当于一个变量名吧
通过浏览器中network可以看到,请求路径变成了localhost,但是其实真实请求地址还是api.xxx.com,障眼法而已
HBuilderX的内部浏览器(需要单独安装浏览器插件)
如果使用uniapp开发,那就要用HBuilderX了,但是本地测试,不习惯用他的,看控制台麻烦,还是外部浏览器比较好,还省着装插件了
总之,这个方法最简单,但我不用
服务器环境(ubuntu + nginx) 跨域解决办法
前后端项目部署在不同域名 或者 相同域名但是端口不同时,前端请求会遇到的跨域问题 对于上面使用了
Proxy代理方式跨域的,部署到服务器环境后,这种方式会失效,需要在nginx重新配置一个
这个配置非常简单,找到网站的nginx配置文件,打开在如下结构的位置处添加一个localtion配置即可
http {
server {
......
location / {
root /var/www/html; #Web网站程序存放目录。
index index.html index.htm;
}
//添加如下配置
location /api233 {
proxy_pass http://api.xxx.com;
}
.....
注:配置修改完毕后,不会立即生效,还需要重启一下
nginx重启方式:直接执行/usr/sbin/nginx -s reload(如果不知道nginx安装在哪里,可以先执行一下whereis nginx)