You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用fetch获取图片触发CORS策略拦截问题求助

问题:Fetch图片触发CORS错误,图片请求未经过index.php

项目情况

  • 开发一款允许用户创建项目并上传最多5张图片的Web应用,采用PHP搭建API
  • 已在index.php中配置CORS规则:
// 指定允许跨域请求的域名
header('Access-Control-Allow-Origin: *');
// 指定允许的请求方法
header('Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS');
// 允许携带的请求头
header('Access-Control-Allow-Headers: X-Requested-With,Authorization,Content-Type');
// 设置缓存有效期1天以提升速度
header('Access-Control-Max-Age: 86400');
// OPTIONS请求直接返回,避免加载完整页面
if (strtolower($_SERVER['REQUEST_METHOD']) == 'options') {
    exit();
}
  • 图片存储在public/img目录,通过php -S localhost:3000 -t public/启动PHP内置服务器
  • 所有API接口路由返回JSON响应,Web应用能正常接收;使用<img src="http://localhost:3000/img/image.jpg">可正常显示图片,直接在浏览器或Postman访问图片地址也无问题

问题现象

使用以下JavaScript代码fetch图片时触发CORS错误:

const image = await fetch(BASE_URL + imagePath); // 实际请求地址:http://localhost:3000/img/image.jpg
const imageBlob= await image.blob();

错误信息:

project.html:1 Access to fetch at 'http://localhost:3000/img/image.jpg' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

排查确认:图片请求未经过index.php

原因分析

使用php -S localhost:3000 -t public/启动服务器时,PHP内置服务器会直接返回public目录下的静态文件(如图片),不会经过index.php。因此index.php中配置的CORS规则仅对通过该文件转发的API请求生效,静态图片请求由服务器直接返回,未携带CORS响应头,导致跨域fetch时触发浏览器的同源策略校验错误。

而<img>标签加载图片属于资源嵌入场景,浏览器对这类请求的CORS校验有例外规则,因此能正常显示;但fetch请求属于跨域数据请求,浏览器会严格校验响应头,缺少Access-Control-Allow-Origin就会报错。

解决办法

方法1:修改PHP内置服务器路由,让所有请求经过统一入口

启动服务器时添加路由规则,将所有请求转发到自定义路由文件处理:

php -S localhost:3000 -t public/ router.php

在项目根目录创建router.php,内容如下:

<?php
// 先处理CORS规则
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: X-Requested-With,Authorization,Content-Type');
header('Access-Control-Max-Age: 86400');

if (strtolower($_SERVER['REQUEST_METHOD']) == 'options') {
    exit();
}

// 处理静态文件请求
$requestUri = $_SERVER['REQUEST_URI'];
$filePath = __DIR__ . '/public' . $requestUri;

// 如果是存在的静态文件,返回文件内容
if (file_exists($filePath) && is_file($filePath)) {
    // 设置对应文件的Content-Type
    $mime = mime_content_type($filePath);
    header("Content-Type: $mime");
    readfile($filePath);
    exit();
}

// 其他请求交给index.php处理
require_once __DIR__ . '/public/index.php';

这样所有请求(包括静态图片)都会经过router.php,自动携带CORS响应头,fetch请求即可正常处理。

方法2:在生产环境Web服务器中配置静态文件CORS头

如果后续使用Nginx/Apache部署,可直接在服务器配置中为img目录添加CORS规则:

  • Nginx配置示例:在server块中添加
location /img/ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods GET,OPTIONS;
}
  • Apache配置示例:在public/.htaccess中添加
<Directory "img/">
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Methods "GET,OPTIONS"
</Directory>

方法3:临时使用no-cors模式(不推荐用于需处理Blob内容的场景)

如果仅需获取Blob但无需读取内容,可设置fetch的mode: 'no-cors',但此时返回的是不透明响应,无法解析Blob内容,仅能用于缓存或嵌入页面等场景:

const image = await fetch(BASE_URL + imagePath, { mode: 'no-cors' });
const imageBlob = await image.blob();
// 注意:该Blob无法正常读取内容,仅可用于如URL.createObjectURL(imageBlob)嵌入页面的场景

内容的提问来源于stack exchange,提问作者Lucas da Paz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 11:52:39