jQuery发起POST请求调用API遇CORS问题,预检请求未返回HTTP OK被拦截
跨域问题根因定位
你当前遇到的拦截是两个独立的问题叠加导致的:
- 非简单请求的预检请求没有被后端正确处理。你发起的请求带
Content-Type: application/json,属于浏览器定义的非简单请求,会自动触发OPTIONS方法的预检流程,但你当前的CORS配置只声明了允许POST方法,完全没有对OPTIONS请求做响应处理。PHP默认不会自动给OPTIONS请求返回200状态,通常会直接走业务逻辑分支返回405、500等错误码,这就是报错提示里“预检请求未返回HTTP OK状态”的直接来源。 - 缺失预检必须的响应头字段。非简单请求的预检流程中,浏览器会检查后端是否明确允许请求携带的
Content-Type自定义头,你当前的配置没有声明Access-Control-Allow-Headers,哪怕OPTIONS请求返回了200,也会因为缺少这个字段被CORS策略拦截。 - 你报错信息里提到的请求来源为null,一般是测试时直接通过
file://协议打开前端HTML文件导致的。这种场景下只要Access-Control-Allow-Origin: *正常返回,本身不会造成拦截,但要额外注意:如果PHP接口在调用header()函数之前有任何输出(比如文件开头的空行、UTF-8 BOM头、PHP闭合标签后的空格、提前抛出的警告信息),会直接导致所有设置的响应头失效,浏览器拿不到CORS配置自然会拦截请求。
可直接复用的修复方案
后端接口调整
按照下面的规则修改create.php文件,所有CORS相关配置必须放在文件最开头,前面不能有任何输出内容:
- 把OPTIONS方法加入允许的请求列表
- 补上缺失的
Access-Control-Allow-Headers配置,匹配请求携带的内容类型 - 收到OPTIONS预检请求时直接返回204成功状态,不执行后续业务逻辑
修改后的核心代码结构参考:
<?php // 所有header配置必须放在文件最开头,前面禁止有空格、BOM、其他输出 header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: POST, OPTIONS"); header("Access-Control-Max-Age: 3600"); // 匹配请求携带的Content-Type头,这是之前漏掉的核心字段 header("Access-Control-Allow-Headers: Content-Type, X-Requested-With"); header("Content-Type: application/json; charset=UTF-8"); // 直接拦截预检请求,返回无内容的成功响应 if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } // 以下为原有的业务逻辑代码(接收POST数据、处理入库等) // ... ?>
配置失效排查要点
如果改完头配置还是被拦截,打开浏览器开发者工具的「网络」面板,找到对应的OPTIONS预检请求做检查:
- 看响应头列表里有没有上述配置的
Access-Control-*字段,如果没有,说明header()函数的调用被提前输出打断了:检查PHP文件开头有没有多余空行、有没有在PHP结束标签?>之后写了空格或内容、文件是不是被保存成了带BOM的UTF-8格式、接口有没有在头设置之前就抛出PHP警告/Notice输出到响应体。 - 如果OPTIONS请求返回404,说明请求路径没有正确匹配到PHP文件,检查本地Apache/Nginx的站点路径配置。
- 如果OPTIONS请求返回500,说明PHP在处理请求时抛出了语法错误或运行时错误,打开PHP错误日志定位具体报错。
前端测试注意事项
- 不要直接用
file://协议打开本地HTML文件做测试,把前端文件放到本地Web服务的站点目录下,通过http://协议访问。这种方式虽然*来源配置能兼容null来源,但后续如果要增加Cookie鉴权、自定义请求头时会出现兼容问题。 - 你现有的jQuery ajax代码不需要做额外调整,匹配后端修复后的配置即可正常运行。
内容的提问来源于stack exchange,提问作者UnhappyEverAfter
相关产品推荐
相关产品推荐

