最近要做一个专门嵌入外部链接或者自定义文章的页面,结果发现一旦在iframe中使用了微信公众号url嵌入就会报错:
于是乎在查阅资料后发现这是因为微信的页面设置了响应头“frame-ancestors 'self'”,简单来说就是微信阻止了外部页面将其嵌入的行为。那么该怎么办呢,我在网上寻找一番之后倒是发现了一些基于jQuery的解决方法,虽然我的项目是VUE移动端项目,不过还是可以借鉴修改一番的,直接上核心部分代码:
getURL(url) {
let http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
let realurl = http + '//cors-anywhere.herokuapp.com/' + url;
let that = this;
$.ajax({
type: 'get',
url: realurl,
success: function (res) {
if (res) {
let data = res;
data = data.replace(/data-src/g, 'src');
let htmlSrc = 'data:text/html;charset=utf-8,' + data; // 解析码解决乱码
that.url = htmlSrc;
}
},
error: function (err) {
console.log(err);
Toast('好像出错了...');
}
});
// axios.get(realurl).then(res=>{
// console.log(res);
// },rej=>{
// let data = rej.data;
// data=data.replace(/data-src/g, "src");
// let html_src = 'data:text/html;charset=utf-8,' + data; //解析码解决乱码
// this.url = html_src;
// })
}
}
首先这个方法的核心就是利用cors-anywhere.herokuapp.com这个服务端的api,将跨域请求发送出去。而本来项目里的ajax请求是用axios的,但是通过axios发送的请求只能在reject中拿到返回值,感觉这样可能不太好,于是乎我换成了zepto的ajax请求方式。而通过这个服务端api返回的data-src属性需要替换成src,最后再放入iframe中的url即可。
完整代码:
<template>
...
<iframe :src="url"></iframe>
...
</template>
<script>
export default {
data: {
details: {},
url: ''
},
created() {
// 从接口取到iframe地址
this.getDetails({id: this.$route.params.id, type: this.$route.params.type})
.then(res => {
this.details = res.data.obj;
let head = this.details.href.slice(0, 24);
if (head === 'https://mp.weixin.qq.com') {// 是微信公众号文章
this.getURL(this.details.href);
} else {// 是其它网址直接使用
this.url = this.details.href;
}
}, rej => {});
},
methods: {
getURL(url) {
let http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
let realurl = http + '//cors-anywhere.herokuapp.com/' + url;
let that = this;
$.ajax({
type: 'get',
url: realurl,
success: function (res) {
if (res) {
let data = res;
data = data.replace(/data-src/g, 'src');
let htmlSrc = 'data:text/html;charset=utf-8,' + data; // 解析码解决乱码
that.url = htmlSrc;
}
},
error: function (err) {
console.log(err);
Toast('好像出错了...');
}
});
// axios.get(realurl).then(res=>{
// console.log(res);
// },rej=>{
// let data = rej.data;
// data=data.replace(/data-src/g, "src");
// let html_src = 'data:text/html;charset=utf-8,' + data; //解析码解决乱码
// this.url = html_src;
// })
}
}
}
</script>
写在后面:这种方法虽然解决了项目的燃眉之急,但还是存在两个问题,第一是从接口取到返回值的时候会报错(内容我还看不太懂,可能因为jQuery和zepto或axios的实现方式不太相同),目前看来不会影响正常使用;第二个就是cors-anywhere.herokuapp.com这是一个第三方的api,如果能够通过自己的后台实现这种代理会更好一点。此外,如果嵌入的页面中带有视频的话,似乎视频会无法播放,这一点有待证实。
参考内容:
JQ-ajax使用CORS-AnyWhere实现任意跨域请求
Content Security Policy directive: "frame-ancestors 'self'
网友评论