Skip to content

A demo collection for cross-origin. / 跨源(跨域)方案的演示集合,包含前后端完整代码。

Notifications You must be signed in to change notification settings

calimanco/cross-origin-demo

Repository files navigation

cross-origin-demo

JavaScript Style Guide

简介

跨源(跨域)方案的演示集合(下统一称跨源),可在本地演示下列方案,包含前后端完整代码。
后端主要基于 Express 开发,前端不依赖任何第三方,源码带有完善注释,力求用最直接简洁的方式让使用者学会跨源方案的原理。
配合本人的解析原理的博客文章食用更加:传送门

  • JSON-P(自填充 JSON)
  • HTML-P/MockForm(自填充 HTML/模拟表单)
  • SubHostProxy(子域名代理)
  • WindowHash
  • WindowName
  • PostMessage
  • CORS / Cross-origin resource sharing(跨源资源分享)

安装

克隆到本地。

git clone https://github.com/calimanco/cross-origin-demo.git

如果你只是演示用,只安装 dependencies 的包即可。

cd cross-origin-demo
npm install --production

使用

请先将下面内容写入本地 hosts 文件。
Win 系统一般是在 c:\windows\system32\drivers\etc\hosts
Mac/Linux 系统一般是在 /etc/hosts

127.0.0.1 demo.com
127.0.0.1 api.demo.com

启动服务器。
该命令将并行启动三个服务,仅 bash 能用。

npm start

非 bash shell 请分别在不同的 shell 窗口运行如下命令:

npm run proxy
npm run server1
npm run server2

打开浏览器访问 demo.com

index

点击上面的连接即可进入该跨源方案的案例界面。

index

服务器布局

本项目共包含三个服务器,均使用 NodeJS 开发,无需依赖其他容器或服务。
基本流程是访问 demo.com 的页面,页面将请求 api.demo.com 的接口,要完成请求就必须进行跨源操作。

  • proxy
    反向代理服务器,监听本地 80 端口,用于将不同域名指向另外两个服务。
  • server1
    Web 服务器,监听本地 3000 端口,演示域名为 demo.com ,提供静态页面和资源。
  • server2
    API 服务器,监听本地 4000 端口,演示域名为 api.demo.com ,包含 Pug 模板渲染器,提供接口供页面调用。

server-layout

目录结构

├── proxy.js                      // 反向代理服务器
├── server1                       // Web 服务器
│   ├── main.js                   // Web 服务器主文件
│   ├── pages                     // 页面目录
│   │   ├── JSONP                 // 每一个跨源方案单独一个目录
│   │   │   ├── index.html        // 该跨源方案的入口
│   │   │   └── request-JSONP.js  // 该跨源请求方法的 Promise 封装
│   │   ├── MockForm
│   │   ├── ...
│   │   └── index.html            // 首页,会列出所有跨源方案的入口
│   └── public                    // 静态资源,包含公共的 JS 和 CSS
└── server2                       // API 服务器
    ├── main.js                   // API 服务器主文件
    ├── router.js                 // 路由集合(接口)
    └── templates                 // 模板目录,render 方法的默认目录

关于取得 iframe 加载状态的 hack 方法

由于同源限制,如果 iframe 内是非同源(domain)的页面,父级页面是无法读取 document 的。
因此利用 iframe 的 onload 事件检查 iframe 内是否加载完毕是不可靠的。
本项目为了解决该问题,给所有 iframe 内页面都加了一个隐藏的 iframe 标签,利用 window.length,来检测页面是否被加载。
window.length 返回的是当前页面内 iframe 的数量,如果成功加载,那将返回 1,如果无法加载,则返回 0,此方法缺点就是无法获取准确的服务器状态(服务器返回的状态码),只能统称为"网络错误"。

iframe.onload = function (event) {
  // We cannot get accurate server status.
  if (event.target.contentWindow.length === 0) {
    // We should throw network error here.
    return
  }
  // do something
}

关于 iframe 会 onload 两次的解决 hack 方法

经过测试在 Chrome、Safari、Edge 等 WebKit 衍生浏览器上 iframe 即使没有设置 src ,也会在 append 进页面后 onload 一次,设置 src 跳转后会 onload 第二次。
本项目几个方案都需要使用 form 去触发 iframe 跳转,因此初始化的第一次 onload 是不符合预期的。
解决办法是在初始化时,设置为 iframe.src = '#'

提示

本项目以演示原理为目的,兼容性不作为编码考虑,代码仅在 Chrome 浏览器和 NodeJS v14+ 测试过,其他的版本环境和浏览器请自行兼容。
本项目代码均不建议直接用于生产环境,仅作为思路参考。

About

A demo collection for cross-origin. / 跨源(跨域)方案的演示集合,包含前后端完整代码。

Topics

Resources

Stars

Watchers

Forks