type
Post
status
Published
date
Sep 3, 2021
slug
fgligg
summary
category
问题记录
tags
Bugs
创建时间
Apr 7, 2023 07:15 PM
更新时间
Apr 10, 2023 05:48 AM
password
icon
Task List
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(); }