配置完全指南:原理、检测方法与 Nginx 实战)
Swagger UI 跨域CORS配置完全指南原理、检测方法与 Nginx 实战【免费下载链接】swagger-uiSwagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.项目地址: https://gitcode.com/GitHub_Trending/sw/swagger-ui本文围绕 Swagger UI 官方文档中关于 CORS跨域资源共享的说明展开系统讲解浏览器为何会拦截跨域请求、Swagger UI 在哪些场景下必须启用 CORS、三种可落地的检测手段以及本仓库 Docker 镜像中基于 Nginx 的完整 CORS 配置实现。读完本文你将能够判断自己的 Swagger 部署是否存在跨域隐患并用 curl 与浏览器控制台快速定位问题最终通过 Nginx 配置或自定义中间件为文档与 API 端点正确开启跨域支持。一、CORS 是什么为何与 Swagger UI 息息相关CORSCross-Origin Resource Sharing跨域资源共享是一种用于防止网站滥用你个人数据的技术手段。绝大多数浏览器和 JavaScript 工具库不仅支持 CORS而且会强制执行它——也就是说当页面所在的源协议 主机 端口与请求目标不一致时浏览器会依据目标服务器返回的 CORS 响应头来决定是否放行这次请求。这一点对 Swagger UI 有直接影响Swagger UI 本质上是一组 HTML、JavaScript 与 CSS 资源运行在浏览器中通过XMLHttpRequest/fetch动态加载你的 API 文档并发送调试请求。只要你的 Swagger 文档地址、$ref引用的外部文档地址或Try it now请求的目标接口与 Swagger UI 页面本身不同源CORS 就会介入并可能直接导致文档加载失败或无法在线调试。W3C 对 CORS 规范有专门的定义详见 http://www.w3.org/TR/cors 对应的标准文档而本仓库的 docs/usage/cors.md 则将这一通用规范落到了 Swagger UI 的实际使用场景中。二、两种无需处理 CORS 的情况根据 docs/usage/cors.md在以下两种情况下你不需要为 CORS 做任何额外配置Swagger UI 与应用托管在同一台服务器上即同主机host且同端口port。此时页面源与请求目标完全一致浏览器不会发起跨域检查应用位于一个已经启用 CORS 响应头的代理之后。例如公司内部的网关、反向代理已经统一注入了Access-Control-*头这种情况下 CORS 可能已经由你的组织内部覆盖。其余情况都需要为以下两类资源显式启用 CORSSwagger 文档本身对于 Swagger 2.0 而言即swagger.json/swagger.yaml以及任何被外部$ref引用的文档API 端点为了让界面上的Try it now在线调试按钮正常工作你的 API 端点同样必须启用 CORS。换句话说即使你的文档加载成功了只要 API 端点没有 CORS 头点击试一下发起请求时依然会被浏览器拦截。三、三种验证 CORS 支持的方法方法一使用 curl 检查响应头直接对接口发起 HEAD 请求并观察响应头是最快、最直观的验证方式。官方文档给出的示例$ curl -I https://petstore.swagger.io/v2/swagger.json HTTP/1.1 200 OK Date: Sat, 31 Jan 2015 23:05:44 GMT Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS Access-Control-Allow-Headers: Content-Type, api_key, Authorization Content-Type: application/json Content-Length: 0以上响应说明petstore 资源支持OPTIONS预检请求并允许携带Content-Type、api_key、Authorization这三个自定义请求头。判断要点有三是否出现Access-Control-Allow-Origin允许的源Access-Control-Allow-Methods是否覆盖Try it now会用到的GET/POST/PUT/DELETE等方法Access-Control-Allow-Headers是否包含你的 API 实际要使用的请求头详见第五节。方法二从文件系统运行 Swagger UI 并查看调试控制台将 Swagger UI 以本地文件方式打开file://协议此时页面源会被浏览器记为null。若目标服务器未启用 CORS浏览器控制台会出现类似下面的错误XMLHttpRequest cannot load http://sad.server.com/v2/api-docs. No Access-Control-Allow-Origin header is present on the requested resource. Origin null is therefore not allowed access.这条报错中的关键信息是No Access-Control-Allow-Origin header is present。需要说明的是Swagger UI 本身很难把这种错误状态直观地呈现在界面上因此排查时要习惯打开开发者工具DevTools的 Network / Console 面板观察真实报错。方法三使用在线 CORS 检测工具可以使用 test-cors.org 这类专门的 CORS 检测站点来验证。但要注意这类工具即使在没有返回Access-Control-Allow-Headers的情况下也可能显示成功而该响应头对于 Swagger UI 正常工作仍然是必需的。因此在线工具只能作为初步筛查最终仍应以第一种 curl 方法中的三个响应头是否齐全为准。四、如何启用 CORS以仓库内置的 Nginx 镜像为例启用 CORS 的具体方式取决于你托管应用的服务器或框架enable-cors.org 等站点汇总了常见 Web 服务器Nginx、Apache、IIS 等的配置方法其他服务器或框架通常也有各自官方的启用说明。本仓库的 Docker 镜像给出了一套开箱即用的 Nginx 实现非常值得作为参考模板。整套机制由三个文件协作完成1. CORS 响应头模板docker/cors.confadd_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods GET, POST, OPTIONS always; # # Custom headers and headers various browsers *should* be OK with but arent # add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type always; # # Tell client that this pre-flight info is valid for 20 days # add_header Access-Control-Max-Age $access_control_max_age always; if ($request_method OPTIONS) { return 204; }逐行解读这份配置Access-Control-Allow-Origin: *允许任意源访问。若需要限定来源可将*替换为具体域名Access-Control-Allow-Methods声明允许的 HTTP 方法。仓库模板给出的是GET, POST, OPTIONSOPTIONS是预检请求必需的方法不能省略如果你的 API 使用了PUT/DELETE/PATCH需要在此追加Access-Control-Allow-Headers声明允许浏览器发送的请求头白名单覆盖了Content-Type、X-Requested-With、Cache-Control、自定义头等常见情况Access-Control-Max-Age告知浏览器预检结果的有效期缓存时长减少重复预检。其取值来自变量$access_control_max_ageif ($request_method OPTIONS) { return 204; }对预检请求直接返回 204No Content避免请求继续落入应用处理逻辑。其中$access_control_max_age变量在 docker/default.conf.template 中通过map指令定义map $request_method $access_control_max_age { OPTIONS 1728000; # 20 days }即仅当请求方法是OPTIONS时缓存时间为 1728000 秒20 天这与模板注释Tell client that this pre-flight info is valid for 20 days完全对应。2. 配置挂载位置docker/default.conf.templateNginx 模板将cors.conf挂载到了三个关键位置location $BASE_URL { absolute_redirect off; alias /usr/share/nginx/html/; expires 1d; location ~ swagger-initializer.js { expires -1; include templates/cors.conf; } location ~* \.(?:json|yml|yaml)$ { #SWAGGER_ROOT expires -1; include templates/cors.conf; } include templates/cors.conf; include templates/embedding.conf; }location ~ swagger-initializer.js对初始化脚本应用 CORS 头保证页面自身的引导资源跨域可加载location ~* \.(?:json|yml|yaml)$对json/yml/yaml后缀的文档文件应用 CORS 头——这正是第一节提到的Swagger 文档本身需要启用 CORS的落地实现根 location 下的include templates/cors.conf;对站点内其余静态资源统一生效。3. 环境变量开关Dockerfile 与启动脚本镜像默认开启 CORS。在 Dockerfile 中可以看到环境变量定义ENV API_KEY**None** \ SWAGGER_JSON/app/swagger.json \ PORT8080 \ PORT_IPV6 \ BASE_URL/ \ SWAGGER_JSON_URL \ CORStrue \ EMBEDDINGfalse而 docker/docker-entrypoint.d/40-swagger-ui.sh 中的逻辑则负责按需关闭# enable/disable CORS if [ $CORS ! true ]; then truncate -s 0 /etc/nginx/templates/cors.conf fi也就是说容器启动时若环境变量CORS不是true启动脚本会把cors.conf模板清空从而让 Nginx 不注入任何 CORS 头保持默认值true则启用。这种模板 启动时裁剪的设计让你无需改动镜像即可通过-e CORSfalse一键关闭跨域支持或通过挂载自定义cors.conf覆盖默认的允许名单。五、CORS 与 Header 参数白名单必须包含你的请求头Swagger UI 允许你在界面上轻松地把某些请求头作为参数随请求一起发送例如在 authorization-popup.jsx 等认证组件中输入api_key、Authorization等头部。但有一个硬性约束这些请求头的名称必须同时出现在服务器的 CORS 配置中。以上文 curl 示例中的响应头为例Access-Control-Allow-Headers: Content-Type, api_key, Authorization浏览器只允许 Swagger UI 发送名字落在上述白名单内的头部如果你的接口依赖某个自定义请求头如X-API-Key而未在Access-Control-Allow-Headers中声明那么即使Access-Control-Allow-Origin配置正确该请求头也会被浏览器拦截Try it now依然无法携带它完成调用。六、跨域场景下的补充能力与已知限制withCredentials跨域携带凭证当你的 API 需要跨域携带 Cookie 等凭证时可以开启 docs/usage/configuration.md 中定义的withCredentials配置项对应环境变量WITH_CREDENTIALS默认false。该选项启用后浏览器发送的跨域请求将按 Fetch 标准携带凭证。它在 src/core/config/defaults.js 中的默认实现如下withCredentials: false,同时需要留意当前 Swagger UI 尚无法跨域设置 Cookie详见 swagger-js 相关 issue #1163因此实际使用中只能依赖浏览器自身持有的 Cookie而这个配置只是允许浏览器把已有 Cookie 随请求发出去。另外当Access-Control-Allow-Origin为*时浏览器通常不允许凭证请求如需使用凭证服务端必须返回具体的源而非通配符。请求/响应拦截器在跨域链路中注入额外处理Swagger UI 的配置中还提供了requestInterceptor与responseInterceptor同样定义于 src/core/config/defaults.js它们会被透传到请求解析与发送环节。以 src/core/plugins/spec/actions.js 中的文档解析逻辑为例resolve阶段会携带这两个拦截器去拉取文档与外部$ref引用return resolve({ fetch, spec: json, baseDoc: String(new URL(url, document.baseURI)), modelPropertyMacro, parameterMacro, requestInterceptor, responseInterceptor }).then(({ spec, errors }) { ... })实际发请求时见 src/core/plugins/auth/actions.js 中的fn.fetch调用这两个拦截器同样被传入。这意味着你可以在请求发出前统一改写头信息、或在响应返回后统一校验 CORS 相关的响应头为跨域调试提供更细粒度的控制。浏览器禁止的请求头Forbidden header names即使服务端在Access-Control-Allow-Headers中声明了某些头浏览器出于安全机制仍然会拒绝由网页代码控制部分禁用请求头Forbidden header names详见 docs/usage/limitations.md。这些头包括Cookie、Cookie2、Host、Referer、Origin、DNT、Connection、Content-Length、Transfer-Encoding、Proxy-*、Sec-*等。其最直接的影响是OpenAPI 3.0 的 Cookie 类型参数在浏览器中运行 Swagger UI 时无法被控制因为网页代码不能直接设置Cookie请求头相关上下文见 issue #3956。因此在设计 API 时若目标使用者是浏览器内的 Swagger UI应优先考虑使用 Header 参数或 OAuth2 等方式传递身份信息而不是 Cookie 参数。七、小结一份可执行的 CORS 检查清单最后将全文要点整理为一份可对照执行的检查清单判断是否同源Swagger UI 页面与文档、API 是否同主机且同端口是则无需处理检查文档资源对swagger.json/swagger.yaml及外部$ref文档执行curl -I确认存在Access-Control-Allow-Origin检查 API 端点对Try it now会调用的接口执行同样的 curl 检查确认Access-Control-Allow-Methods覆盖实际方法、OPTIONS预检可正常返回核对请求头白名单Access-Control-Allow-Headers必须包含 Swagger UI 界面会发送的所有头部如Authorization、api_key及自定义头按需调整部署使用本仓库 Docker 镜像时可通过CORS环境变量开关与cors.conf模板定制响应头自行部署时可参照 docker/cors.conf 在 Nginx 中实现同等配置留意浏览器限制Cookie 参数与禁用请求头无法在浏览器环境中生效必要时改用withCredentials配合具体源的白名单或调整认证方案。完成以上检查后你的 Swagger UI 即可在跨域场景下稳定加载文档并正常使用在线调试能力。【免费下载链接】swagger-uiSwagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.项目地址: https://gitcode.com/GitHub_Trending/sw/swagger-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考