跨域场景汇总


Access-Control-Allow-Origin 相关

问题出现

No ‘Access-Control-Allow-Origin’ header is present on the requested resource,但是 status 200 OK

Access to XMLHttpRequest at 'http://xxx/get' from origin 'http://ccc' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这种现象是服务器端后台允许 OPTIONS 请求,并且接口也允许 OPTIONS 请求,但是头部匹配时出现不匹配现象.
比如 origin 头部检查不匹配,比如少了一些头部的支持(如常见的 X-Requested-With 头部),然后服务端就会将 response 返回给前端,前端检测到这个后就触发 XHR.onerror,导致前端控制台报错.

解决办法

增加跨域中间件:

import { Context } from "koa";

/**
 * 跨域白名单
 */
enum WhiteList {
  DEV = 'http://dev-xxx.com:6666',
  TEST_HTTP = 'http://test.com',
  TEST_HTTPS = 'https://test.com',
  PROD_HTTP = 'http://prod.com',
  PROD_HTTPS = 'https://prod.com',
}

/**
 * 跨域中间件
 * @param ctx 上下文拿到Origin来判断是否是跨域请求
 * @param next 如果是跨域就设置允许的源和Headers,再放行
 */
export async function CORSMiddleware(ctx: Context, next: (err?: any) => Promise<any>): Promise<any> {
  // 获取 Origin 请求头,只有非简单请求时,浏览器才会带上Origin字段来标识
  const requestOrigin = ctx.get('Origin');

  // 不管有没有跨域都要设置 Vary: Origin
  ctx.set('Vary', 'Origin')

  const whiteList = Object.values(WhiteList) as string[]

  // 1.如果没有设置,说明没有跨域,跳过
  // 2.或者 不在域名白名单中这直接跳过
  if (!requestOrigin || !whiteList.includes(requestOrigin)) {
    return await next();
  }
  // 设置响应头
  ctx.set('Access-Control-Allow-Origin', requestOrigin)
  // 跨域解决
  ctx.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
  ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
  // 该字段可选,用来指定本次预检请求的有效期,单位为秒。
  // 当请求方法是PUT或DELETE等特殊方法或者Content-Type字段的类型是application/json时,服务器会提前发送一次请求进行验证
  // 下面的的设置只本次验证的有效时间,即在该时间段内服务端可以不用进行验证
  ctx.set("Access-Control-Max-Age", '86400');
  return await next();
}

文章作者:   1874
文章链接:   https://1874.cool/fgligg/
版权声明:   本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 1874 !
评论
  目录