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
相关产品推荐
相关产品推荐

