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

Rails 6 API对接React时CORS请求返回200但无法读取响应数据

Rails 6 API对接React前端跨域请求返回200但无法读取数据问题

问题背景

  • 后端采用Ruby on Rails 6开发REST API,前端为运行在localhost:3005的React应用
  • 接口测试情况:通过Postman、Curl测试GET接口均可返回预期响应;浏览器网络面板可查看到后端返回正确的餐品JSON数据,但页面DOM未渲染对应内容,fetch返回的response对象无法正常读取,response.ok属性值为false,状态码显示200

现象截图

  • Firefox控制台截图:Firefox控制台报错
  • 后端返回数据截图:后端响应数据
  • DOM未渲染数据截图:页面无数据渲染

相关代码与响应内容

1. React前端useEffect数据请求逻辑

useEffect(() => {
  const fetchMeals = async () => {
    const response = await fetch("http://localhost:3000/meals.json", {
      'method': 'GET',
      'mode': 'no-cors',
      'headers': {
        'Origin': 'localhost:3000',
        'Access-Control-Allow-Origin': '*',
      }
    });

    if (!response.ok) {
      throw new Error("The data could not be shown");
    }

    const responseData = await response.json(); 
    const loadedMeals = [];

    for (const key in responseData) {
      loadedMeals.push({
        id: key,
        name: responseData[key].name,
        description: responseData[key].description,
        price: responseData[key].price,
      });
    }

    if (!loadedMeals.length) {
      throw new Error("No products found to display");
    } else {
      setMeals(loadedMeals);
      setIsLoading(false);
    }
  };

  fetchMeals().catch((error) => {
    setIsLoading(false);
    setHttpError(error.message);
  });
}, []);

2. Rails后端cors跨域配置

配置文件路径:config/initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'localhost:3005', '127.0.0.1:3005'

    resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

3. MealsController控制器代码

class MealsController < ApplicationController
    #get /meals
    def index
        @meals = Meal.all
        render json: @meals
    end
end

4. Meal模型代码

class Meal < ApplicationRecord
    def as_json(options = {})
        super(:only => [:id, :name, :description, :price])
    end
end

5. 后端实际返回JSON内容

[
    {
        "id": 1,
        "name": "Cheese and Loroco",
        "description": "Corn made pupusa with cheese",
        "price": "1.25"
    },
    {
        "id": 2,
        "name": "Cheese and red deans",
        "description": "Corn made pupusa with cheese and beans",
        "price": "0.65"
    },
    {
        "id": 3,
        "name": "Pork, cheese and red beans",
        "description": "Corn made pupusa with a mix of pork,cheese and red beans",
        "price": "0.85"
    },
    {
        "id": 4,
        "name": "Soda",
        "description": "Salvadoran soda beverages",
        "price": "0.65"
    },
    {
        "id": 5,
        "name": "Coffee",
        "description": "High quality roasted salvadoran coffee",
        "price": "1.1"
    }
]

核心疑问

  • 浏览器网络面板已明确显示后端返回了正确的响应数据,为何前端代码无法读取
  • 请求返回200状态码的情况下,response.ok为false、无法解析响应JSON的原因

问题根因

核心错误是前端fetch请求配置了mode: 'no-cors':

  1. 该模式下浏览器会正常发送请求、接收响应,但完全禁止前端JavaScript读取响应内容、状态头等任何信息,返回的是opaque(不透明)响应对象。这类对象的ok属性固定为false,status固定为0,响应体不可读,这就是网络面板能看到数据、但代码拿不到的直接原因。
  2. 请求头里手动添加的Origin和Access-Control-Allow-Origin完全无效:Origin是浏览器自动生成的安全类请求头,禁止前端代码手动篡改;Access-Control-Allow-Origin是后端返回的响应头字段,放在请求里没有任何作用。
  3. 后端的CORS配置本身是正确的,已经放行了3005端口的前端请求,完全不需要使用no-cors模式。

修复方案

  1. 调整前端fetch请求配置,删除mode: 'no-cors'配置项,同时删除headers里手动加的两个无效字段,简化后的请求代码如下:
const response = await fetch("http://localhost:3000/meals.json", {
  method: 'GET'
});
  1. 检查后端依赖与服务状态:确认Gemfile中已添加gem 'rack-cors'并执行过bundle install,修改cors配置后必须重启Rails服务才能让配置生效。
  2. 优化数据处理逻辑:后端直接返回的是数组结构的餐品数据,不需要用for...in遍历对象转数组,拿到responseData后可以直接赋值使用,无需额外格式转换。

内容的提问来源于stack exchange,提问作者htamayo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 19:24:31