咚咚技术团队
  • 首页
  • 文章
    • 前端
      • 0.1 + 0.2 精度丢失深究
      • IOS H5 视频无法播放
      • H5 播放 amr 音频文件
      • IOS 10.x 版本在 Taro 中的兼容性问题
      • 百度 UEditor 引发的 cross-iframe 问题解决方案
      • 访问 www.banchengyun.com 时发生了什么
      • decodeURIComponent 与特殊符号
      • 前端埋点
    • 后端
      • Swoole 相关
        • MAC 本地环境执行 GuzzleHttp 时导致 Swoole 进程异常退出
      • Hyperf 相关
        • 在 phpstorm 中调试 hyperf 代码
        • Hyperf 1.x Proxy 缓存失效问题
      • K8s 相关
        • 搭建 k8s 集群
        • 使用 docker-compose 快速搭建 Hyperf + Redis 开发环境
        • Kubernetes Autoscaler
      • 其它
        • 幂等性和原子性
    • 测试
    • 效能提升
      • 优秀开发者的第一步:始于需求分析
      • 优秀开发者的第二步:如何阅读他人的代码
  • 活动
  • 课堂
  • 知识库
    • 公共
      • 什么是流程型组织
      • 半城云集成产品开发流程
      • 阿⾥云 Codeup 代码平台使⽤ & 迁移指南
      • git 使用规范
      • 关于第三方与服务号授权的问题
      • 收不到消息的排查方法
      • 系统安全
      • 前端编码规范
      • 后端编码规范
      • 测试规范
    • 前端
      • 规范
        • 前端编码规范
        • 咚咚技术栈
        • code-review 规范
        • git 工作流
        • Tapd 文档
      • 复盘经验
        • 2021.01 效能、规范、技术债讨论会
      • Code Review
        • SCRM 2020-07
    • 后端
      • 复盘经验
        • SCRM 2020 年 8 月
      • Code Review
        • SCRM 2020-07
    • 测试
      • 复盘经验
        • SCRM 2020 年 8 月
  • 项目文档
    • 前端
    • 后端:小程序
    • 后端:企业微信
  • 接口文档
  • 兴趣小组
    • golang 小组
    • 增长小组
    • 前端小组
  • 书单推荐
  • 生产环境 分析会
    • NO.2022.01
  • 生产环境 可用性
  • 团队活动
    • OpenTalk
      • NO.2021.Q3
      • NO.2020.Q2
    • WalkTogether
  • 关于我们
  • GitBook 使用说明
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 文章
  2. 前端

百度 UEditor 引发的 cross-iframe 问题解决方案

转载自:半城云 Techer 群

作者:半城云技术赋能组组长 吴泫霖

UEditor 是一个富文本编辑器在公司的业务中广泛应用, 但由于浏览器的同源策略导致了一个 cross-iframe 的问题, 此文章来探讨这个问题以及分享一个解决方案

同源策略是现代浏览器的一个重要的安全机制, 我们遇到的场景是在dev-zhike.banchengyun.com下要把 UEditor 作为 iframe 嵌入, 而dev-zhike.banchengyun.com域名指向的是我们的服务器, 而 UEditor 则是放在 OSS 上以 CDN 域名访问, 如果我们直接嵌入会遇到这个错误

Uncaught DOMException: Blocked a frame with origin “https://web-static.cdn.banchengyun.com” from accessing a cross-origin frame

原因是浏览器不允许嵌入一个不同源(origin)的 iframe, 解决这个问题的方法只有让当前页面和 iframe 是在同一个源下, 这篇文章重点讨论解决思路和方案, 具体的同源机制和 cross-iframe 问题自行百度

实现这个方案看起来也非常简单, 只需要把 UEditor 的文件放到服务器下就可以使用dev-zhike.banchengyun.com的域名访问了, 如果这么实现那浏览器在加载 UEditor 的资源文件时流量就会从服务器的出口流出, 而服务器的出口带宽是非常珍贵的, 而且现有的服务器架构也不支持这种方案, 因为服务器只运行了后端的服务, 图片以及前端的资源文件都是存放在 OSS 上的

既然资源文件不能放到服务器上, 那可以在服务器上搭建一个反向代理把客户端请求代理到 OSS 上

浏览器 -> Nginx -> OSS

对应的 nginx 配置如下

server {
  listen 80;
  server_name dev-zhike.banchengyun.com;

  location ~ /ueditor/(.*)$ {
    proxy_pass https://web-static.cdn.banchengyun.com/$1;
  }
}

这个方案可以实现使用dev-zhike.banchengyun.com域名访问 UEditor 资源文件, 但是如上文所述浏览器加载资源的流量还是会从服务器出口流出, 所以这个方案没有完全解决问题

转换一下思路, 浏览器加载文件是会追随跳转的, 比如有http://foo.com/1.js重定向到http://bar.com/1.js, 使用script标签加载http://foo.com/1.js时浏览器会自动追随跳转到http://bar.com/1.js, 应用到上面的场景可以想到dev-zhike.banchengyun.com的域名只返回 301 跳转指示让浏览器去加载 OSS 的文件

浏览器 -> nginx
            <- 301 location: https://web-static.cdn.banchengyun.com/ue.js
            -> Get https://web-static.cdn.banchengyun.com/ue.js

对应的 nginx 配置如下

server {
  listen 80;
  server_name dev-zhike.banchengyun.com;

  location /ueditor {
        rewrite /ueditor/(.*)$ https://web-static.cdn.banchengyun.com/$1 permanent;
  }
}

此时访问https://dev-zhike.banchengyun.com/ueditor/all.js, nginx 会返回以下响应

content-type: text/html
date: Wed, 25 Aug 2021 10:28:14 GMT
location: https://web-static.cdn.banchengyun.com/ueditor/all.js
server: nginx/1.20.0
content-length: 169

<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.20.0</center>
</body>
</html>

这样就减小了服务器的出口流量, 但是这并没有完全解决问题, 在dev-zhike.banchengyun.com以下面的代码嵌入 iframe 还是会遇到问题

<iframe src="https://dev-zhike.banchengyun.com/index.html"></iframe>

第一个问题是浏览器会自动下载index.html这个文件, 原因是 OSS 在处理html文件会强制加入content-disposition attachment这个响应头, 这个头会触发浏览器的下载行为, 由于用的是 rewrite 指令 nginx 没办法脱掉这个头, 所以需要对 html 文件做一下特殊处理, 改用proxy_pass指令进行反向代理然后脱掉这个头再把内容返回给浏览器

server {
  listen 80;
  server_name dev-zhike.banchengyun.com;

  location ~ .html$ {
    proxy_hide_header Content-Disposition;
    proxy_pass https://web-static.cdn.banchengyun.com$uri;
  }

  location /ueditor {
        rewrite /ueditor/(.*)$ https://web-static.cdn.banchengyun.com/$1 permanent;
  }
}

这样.html 后缀的文件就会命中第一个location块, 上面说到反向代理的流量是要经由服务器出口流出的, 但是 html 文件体积在可接受范围内所以可以忽略这个问题

但是问题并没有完全解决, 此时浏览器报错

Uncaught DOMException: Blocked a frame with origin “https://dev-zhike.banchengyun.com” from accessing a cross-origin frame

最后贴上实际场景的 nginx 配置

    map $http_host $ue_path {
      dev-zhike.banchengyun.com scrm/public/js/ueditor-v1;
      zhike.banchengyun.com scrm/public/js/ueditor-v1;
      dev-yunying.banchengyun.com mall/public/ueditorV6;
      yunying.banchengyun.com mall/public/ueditorV6;
      pre-yunying.banchengyun.com mall/public/ueditorV6;
      default "";
    }

    server {
      listen 80;
      resolver 114.114.114.114;

      location ~ .html$ {
        if ( $ue_path = "" ) {
          return 404;
        }

        proxy_hide_header Content-Disposition;
        add_header X-Frame-Options sameorigin always;
        proxy_pass "https://bcy-web-static.oss-cn-hangzhou-internal.aliyuncs.com/$ue_path$uri";
      }

      location / {
        if ( $ue_path = "" ) {
          return 404;
        }

        rewrite . "https://web-static.cdn.banchengyun.com/$ue_path$uri" permanent;
      }
    }

可以看到与上面分析的差不多, 只是多了一个map结构, 因为不同项目引入的 UEditor 是放在不同的 OSS 位置的

上一页IOS 10.x 版本在 Taro 中的兼容性问题下一页访问 www.banchengyun.com 时发生了什么

最后更新于3年前

这有帮助吗?

观察一下报错的内容发现域名和一开始的不一样了, 这个问题还是浏览器的安全策略导致的, 默认情况下一个网页是不允许以 iframe 方式嵌入到另外一个网页的, 比如无法将百度作为 iframe 嵌入到我们的页面中, 但是有一个 HTTP 头能修改这个行为, 即头, 这个头有两种取值: 第一种是deny, 也就是拒绝所有嵌入行为也是默认行为, 第二种是sameorigin, 允许同源嵌入, 只需要在location ~ .html$块加入add_header X-Frame-Options sameorigin always;指令即可解决问题

X-Frame-Options