Rails 5 API 数据库连接断开时返回自定义JSON响应解决方案咨询
解决方案
1. 控制器层全局捕获数据库连接异常
在app/controllers/application_controller.rb中添加全局异常捕获逻辑,这是最简便的实现方式:
class ApplicationController < ActionController::API # 捕获所有数据库连接相关异常 rescue_from ActiveRecord::ConnectionNotEstablished, Mysql2::Error::ConnectionError, ActiveRecord::StatementInvalid, with: :handle_database_unavailable private def handle_database_unavailable # 返回503服务不可用状态码,符合HTTP语义 render json: { error: "Database unavailable" }, status: :service_unavailable end end
注意:开发环境默认会展示异常详情页,如需测试该效果,可修改config/environments/development.rb中的config.consider_all_requests_local = false
2. 可选:添加Rack中间件实现更前置的拦截
如果需要在请求进入控制器层之前就完成数据库状态检查(避免部分前置插件触发连接异常无法被控制器捕获),可以自定义Rack中间件:
- 新建
app/middleware/database_connection_check.rb
class DatabaseConnectionCheck def initialize(app) @app = app end def call(env) # 提前检查数据库连接是否可用 ActiveRecord::Base.connection.verify! @app.call(env) rescue ActiveRecord::ConnectionNotEstablished, Mysql2::Error::ConnectionError [503, { "Content-Type" => "application/json" }, [{ error: "Database unavailable" }.to_json]] end end
- 在
config/application.rb中注册中间件,放在中间件链的靠前位置:
config.middleware.insert_before 0, DatabaseConnectionCheck
3. 优化数据库连接超时配置
在你的database.yml的default块中添加超时参数,避免连接异常时请求长时间卡住:
default: &default adapter: mysql2 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: XXXX password: XXXX host: XXXX.com port: 3306 encoding: utf8mb4 # 新增超时配置,单位为秒 connect_timeout: 2 read_timeout: 3 write_timeout: 3
关于旧版本Rails静态页可正常访问的说明
旧版本Rails处理静态资源请求时,不会主动触发数据库连接获取;现在的Rails版本尤其是API模式下,默认不托管静态资源,生产环境静态资源一般由Nginx等反向代理直接处理,所有进入Rails进程的请求基本都会触发业务逻辑、主动获取数据库连接,因此会出现全应用不可用的表现。如果有不需要依赖数据库的接口,可以在中间件或者控制器中跳过数据库连接检查逻辑。
内容的提问来源于stack exchange,提问作者Hussain Niazi
相关产品推荐
相关产品推荐

