tips:在iframe中嵌入微信公众号文章

欢迎访问我的简书

最近要做一个专门嵌入外部链接或者自定义文章的页面,结果发现一旦在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’

你可能感兴趣的:(前端应用)