CORS 的 preflight 机制

昨天帮某客户配置 wordpress 的 SSL,本以为是个很简单的活儿,结果遭遇问题,弄了很久才解决。在此过程中对跨域访问的预检机制有了较多的了解,在此记录。

需求:
之所以要将该 wordpress 网站升级为整站 https,除了网站本身的安全性和对外形象之外,最主要是该网站的文章是另外一个 web 应用的数据来源。具体来说,是客户另外那个 web 应用通过 rest api 获取该网站的文章列表并显示。而 web 应用已经率先整站 https,若其通过基于未加密的 http 协议来访问该 wordpress 网站的 rest api,浏览器中会有安全提醒。

第一步:
客户 wordpress 网站基于 centos7,apache2.4.6,php7.0 等。帮客户升级至 php7.4,安装 certbot 配置 let‘s encrypt 证书并配置自动续期,配置安全规则允许 443 端口访问。https 成功可以访问,初步成功。

问题1:
虽然网站在浏览器中可以使用 https 进行访问,但客户的 web 应用上对该网站的 rest api 请求却失败。仔细查看浏览器控制台输出,发现报的错误是:Cross origin resource sharing error: MissingAllowOriginHeader。含义是在 rest api 的 HTTP 响应头中,没有包含 Access-Control-Allow-Origin 的 header。

解决1:
WordPress 虽然是全球用量很大的 CMS 系统,但其文档及社区却不敢恭维,主要是因为其版本众多,各种网络文章针对不同版本不容易分辨,且 PHP 这门世界上最好的语言实在太容易各种 hack,所以对于一个问题的解决方案也是八仙过海,各显神通,良莠不齐。了解到 wordpress 默认不允许跨域访问。经过试验各种配置(包括调整 apache 的默认配置和 VirtualHost 配置,调整 wordpress 的.htaccess 文件内的配置),最后使用的方案是在 wordpress 的 wp-include 文件夹下修改 function.php 实现跨域访问的域名白名单。

问题2:
前一步成功以后,查看浏览器中该 api 访问的预检仍然报错:Cross origin resource sharing error: HeaderDisallowedbyPreflightresponse。这是提示请求头中有不允许的 header,通过排查,发现是请求方应用中有某几个自定义的请求头,通过在服务器端设置 Access-Control-Allow-Headers 而成功。