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

Ruby on Rails使用Faraday Gem如何正确重发带Body的POST请求

根因分析

  • IO流重复读取失效:request.body 属于IO流对象,第一次调用read()方法读取内容后,流指针会移动到末尾,后续再次调用read()只能获取到空字符串,这是JSON解析报错的直接原因。
  • Faraday请求格式配置错误:初始化Faraday时启用了url_encoded请求中间件,该中间件会默认将请求体按表单格式编码处理,你传入的原始JSON字符串会被误识别为表单键名,最终出现在下游服务的params参数中,而非请求体里。

解决方案

步骤1:缓存请求体内容,避免重复读取IO流

只读取一次request.body,将原始内容存到变量中,后续校验和重发都复用该变量:

# 仅读取一次IO流,缓存原始请求体
raw_body = request.body.read
products = JSON.parse(raw_body)
JSON::Validator.validate!(products_schema, products)

步骤2:修正Faraday请求配置

两种可选的配置方式,都可以正确发送JSON格式请求:

方式1:直接发送原始JSON字符串

移除url_encoded中间件,明确指定请求头Content-Type为application/json:

f_headers = {
  'Content-Type' => 'application/json',
  # 其余原有自定义头信息
}
conn = Faraday.new(headers: f_headers) do |f|
  f.response :logger
  f.adapter  Faraday.default_adapter
end

resp = conn.post('http://api2.com/products') do |req|
  req.body = raw_body # 复用缓存的原始JSON内容
end
resp.body

方式2:使用Faraday JSON中间件自动序列化

启用json请求中间件,直接传入解析后的结构化数据,中间件会自动完成JSON序列化和请求头设置:

f_headers = {
  # 自定义头信息
}
conn = Faraday.new(headers: f_headers) do |f|
  f.request :json # 自动序列化请求体+设置Content-Type头
  f.response :logger
  f.adapter  Faraday.default_adapter
end

resp = conn.post('http://api2.com/products') do |req|
  req.body = products # 直接传入校验后的结构化数据即可
end
resp.body

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 14:36:04