React/Rails应用Fetch访问Rails后端遇500错误,求排查解决
React/Rails API 连接失败排查与解决
问题背景
在React/Rails应用中尝试访问API后端,参考某过时教程调整后仍无法正常连接,需排查错误并找到解决方法。
错误信息
前端Fetch控制台错误
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
Rails服务器日志错误
Started GET "/api/v1/playlists/index" for ::1 at 2024-09-05 08:59:11 -0400 Processing by Api::V1::PlaylistsController#index as */* Playlist Load (0.4ms) SELECT "playlists".* FROM "playlists" ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index' ActiveStorage::Attachment Load (0.2ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 1], ["record_type", "Playlist"], ["name", "image"], ["LIMIT", 1]] ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index' ActiveStorage::Blob Load (0.1ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/api/v1/playlists_controller.rb:5:in `index' Completed 500 Internal Server Error in 51ms (ActiveRecord: 0.7ms | Allocations: 7845) fatal (exception reentered):
相关代码片段
React组件:javascript/components/Playlists.jsx(截断版)
import { Table, message, Popconfirm } from "antd"; import React from "react"; class Playlists extends React.Component { ... loadPlaylists = () => { const url = "api/v1/playlists/index"; fetch(url) .then((data) => { if (data.ok) { return data.json(); } console.log(data.json()) throw new Error("Network error."); }) ... }; ... render() { return ( <> <Table className="table-striped-rows" dataSource={this.state.playlists} columns={this.columns} pagination={{ pageSize: 5 }} /> </> ); } } export default Playlists;
Rails控制器:controllers/api/v1/playlists_controller.rb
class Api::V1::PlaylistsController < ApplicationController # GET /playlists or /playlists.json def index @playlists = Playlist.all render json: @playlists end end
Rails路由:routes.rb
Rails.application.routes.draw do root 'page#index' namespace :api do namespace :v1 do get 'playlists/index' post 'playlists/create' delete 'playlists/:id', to: 'playlists#destroy' end end end
更新发现
将控制器中的Playlist.all替换为其他模型(如Track模型,包含YouTube视频ID及播放列表关联)时,接口可正常工作:
class Api::V1::PlaylistsController < ApplicationController # GET /playlists or /playlists.json def index @playlists = Track.all render json: @playlists end end
此时无500错误,仅因字段不同导致表格内容不完整,但能正常获取Track数据。
解决步骤
1. 定位核心问题
前端收到HTML而非JSON,说明Rails在触发500错误时返回了默认错误页面,而非JSON响应。结合更新发现,问题出在Playlist模型的JSON序列化过程中——默认序列化无法处理模型中的ActiveStorage附件关联。
2. 修复Playlist模型序列化问题
方法一:临时排除附件字段验证
先验证是否为附件序列化导致的错误,修改控制器代码:
def index @playlists = Playlist.all render json: @playlists.as_json(except: [:image]) # 排除ActiveStorage关联字段 end
如果请求正常,说明确实是附件序列化的问题。
方法二:显式包含ActiveStorage附件信息
如果需要返回附件数据,调整序列化逻辑:
def index @playlists = Playlist.all render json: @playlists, include: { image_attachment: { include: :blob } } end
方法三:使用自定义序列化器(推荐)
安装active_model_serializers gem,创建自定义序列化器精确控制返回字段:
# app/serializers/playlist_serializer.rb class PlaylistSerializer < ActiveModel::Serializer attributes :id, :name, :description # 按需添加字段 has_one :image_attachment, serializer: ActiveStorageAttachmentSerializer end
控制器中使用序列化器:
def index @playlists = Playlist.all render json: @playlists, serializer: PlaylistSerializer end
3. 优化API错误响应
在API控制器中添加错误捕获,确保500错误时返回JSON而非HTML:
class Api::V1::PlaylistsController < ApplicationController rescue_from StandardError, with: :render_internal_server_error def index @playlists = Playlist.all render json: @playlists end private def render_internal_server_error(exception) render json: { error: exception.message }, status: :internal_server_error end end
4. 路由规范优化(可选)
遵循Rails RESTful规范,调整路由:
Rails.application.routes.draw do root 'page#index' namespace :api do namespace :v1 do resources :playlists, only: [:index, :create, :destroy] end end end
同时更新React中的请求URL为/api/v1/playlists。
内容的提问来源于stack exchange,提问作者Jillian Hoenig
相关产品推荐
相关产品推荐

