CORS 机制

浏览器出于安全性的考虑,会限制 JavaScript 发送的跨源 HTTP 请求,只允许访问与当前网页相同协议,相同域名,相同端口的资源。但是有些场景下需要利用跨源请求,为此提供了 CORS(Cross-origin resource sharing)机制。

CORS 机制基于 HTTP Headers,将是否允许跨源请求的权力交给服务器,服务器通过 HTTP Headers 标识是否允许除它以外的 Origin 的请求。

当 JavaScript 发送跨源 HTTP 请求时,浏览器会为请求附加一些头信息:

  • Origin:指定请求来源
  • Access-Control-Request-Method:CORS 请求使用的 HTTP 方法(非简单请求)
  • Access-Control-Request-Headers:CORS 请求额外发送的头信息字段(非简单请求)

服务器根据 Origin 来决定是否同意这次请求。如果同意请求,服务器发回的 HTTP 响应中会增加头信息:

  • Access-Control-Allow-Origin: 接收的 Origin 的值,或者 * 表示接受任意源的请求
  • Access-Control-Allow-Credentials: 可选,如果有的话值为 true,表示是否允许发送 Cookie
  • Access-Control-Expose-Headers: 可选,指定额外的返回头字段
  • Access-Control-Allow-Methods:, 分割的字符串,内容是支持请求的方法(非简单请求)
  • Access-Control-Allow-Headers:, 分割的字符串,内容是支持请求的字段(非简单请求)
  • Access-Control-Max-Age:跨源请求节点的有效期,单位秒(非简单请求)

Koa 服务端实现

Koa 服务端实现 CORS 机制,最简单的方式就是任何请求都直接返回 Access-Control-* 相关的 header,表示允许跨域请求:

const fs = require("fs");
const path = require("path");

const Koa = require("koa");
const bodyParser = require("koa-bodyparser");

const app = new Koa();
app.use(bodyParser());

app.use(async (ctx, next) => {
    ctx.set("Access-Control-Allow-Origin", "*");
    // ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
    ctx.set("Access-Control-Allow-Methods", "OPTIONS, GET, PUT, POST, DELETE");
    ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");
    ctx.set("Access-Control-Allow-Credentials", true);
    ctx.set("Access-Control-Max-Age", 300);

    ctx.set("Content-Type", "application/json;charset=utf-8");

    if (ctx.request.method == "OPTIONS") {
        ctx.response.status = 200
    } else {
        await next();
    }
})

app.use(async ctx => {
    const params = {
        ...ctx.request.query,
        ...ctx.request.body,
        ...ctx.request.authInfo,
    };

    ctx.body = params;
});

app.listen(5000, () => {
    console.log("Server start at 5000...");
});

// 将主进程ID写入pid文件
const pidfile = path.join(__dirname, "app.pid");
fs.writeFileSync(pidfile, process.pid);

// 脚本停止或重启应用时删除pid文件
process.on("SIGTERM", () => {
    if (fs.existsSync(pidfile)) {
        fs.unlinkSync(pidfile);
    }
    process.exit(0);
});

参考

  • 跨域资源共享 CORS 详解: http://www.ruanyifeng.com/blog/2016/04/cors.html