Ruby发送JSON请求


86

如何在ruby中发送JSON请求?我有一个JSON对象,但我认为我做不到.send。我必须要用JavaScript发送表格吗?

还是可以在ruby中使用net / http类?

与标头-内容类型= json和正文json对象?

Answers:


76
uri = URI('https://myapp.com/api/v1/resource')
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req.body = {param1: 'some value', param2: 'some other value'}.to_json
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
  http.request(req)
end

8
我喜欢您的建议,使用URI来处理主机名和端口,否则非常乏味。但是您忘了在Post.new(...)中设置uri.path:req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols 2014年

1
最简单,最干净的响应。这很棒。
joelc

http.request(req).read_body阅读响应正文。大!
iGian

1
我很确定它在2.4.1中已更改,但我的天哪。这种语法是粗俗的。它知道它具有Post.new()中的URI,所以为什么要在start()中传递值(拆分后)。毛。难怪在ruby中还有这么多其他处理HTTP的软件包。
Rambatino '18

50
require 'net/http'
require 'json'

def create_agent
    uri = URI('http://api.nsa.gov:1337/agent')
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
    req.body = {name: 'John Doe', role: 'agent'}.to_json
    res = http.request(req)
    puts "response #{res.body}"
rescue => e
    puts "failed #{e}"
end

应该指定哪个例外
Mio

7
对于https请求,只需添加:http.use_ssl = true。
技能M2

17

我认为HTTParty使这变得容易一些(并且可以与嵌套的json等一起使用,在我见过的其他示例中似乎不起作用。

require 'httparty'
HTTParty.post("http://localhost:3000/api/v1/users", body: {user: {email: 'user1@example.com', password: 'secret'}}).body

6

真实示例,通过NetHttps通知Airbrake API有关新部署的信息

require 'uri'
require 'net/https'
require 'json'

class MakeHttpsRequest
  def call(url, hash_json)
    uri = URI.parse(url)
    req = Net::HTTP::Post.new(uri.to_s)
    req.body = hash_json.to_json
    req['Content-Type'] = 'application/json'
    # ... set more request headers 

    response = https(uri).request(req)

    response.body
  end

  private

  def https(uri)
    Net::HTTP.new(uri.host, uri.port).tap do |http|
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
  end
end

project_id = 'yyyyyy'
project_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
url = "https://airbrake.io/api/v4/projects/#{project_id}/deploys?key=#{project_key}"
body_hash = {
  "environment":"production",
  "username":"tomas",
  "repository":"https://github.com/equivalent/scrapbook2",
  "revision":"live-20160905_0001",
  "version":"v2.0"
}

puts MakeHttpsRequest.new.call(url, body_hash)

笔记:

如果您通过Authorization标头集标头req['Authorization'] = "Token xxxxxxxxxxxx"http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html进行身份验证


...但是说实话,这很酷,几乎所有内容都可以使用,请直接使用HTTParty stackoverflow.com/a/14491995/473040 :) ...尤其是如果您正在处理https处理
等效8年8

要求uri是没有用的,因为net / http已经要求它
noraj

@ equivalent8:“在现实生活中,我只会使用HTTParty”-也就是说,除非您要构建精简的gem,否则不要其他依赖项。:)
塞尔吉奥·图伦采夫

@SergioTulentsev同意...除非您要在不希望引入不必要依赖的地方建立gem / lib(或基于Ruby的微服务),否则)
等效时间

4

一个简单的json POST请求示例,针对那些需要它的人,甚至比Tom链接到的内容更简单:

require 'net/http'

uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})

19
看起来应该可以使用,但是post_form将参数转换为?key = value&key = value语法。如果您想在请求正文设置为JSON字符串的情况下进行POST,我认为您需要其他解决方案。
Ben Gotow

这不适用于深度嵌套的json。超出第一级的所有内容都将成为字符串。
neoneye 2014年

不仅看起来像。有用。很简单。但是对于简单的事情(例如我给出的示例),它就可以正常工作
Christoffer

4
从根本上讲,这不是JSON请求。这是一个未编码的身体。没有JSON。标头甚至说了很多。这永远不会与任何示例一起使用。
raylu

4
这个答案是不正确的。这是mime / multipart中的POST,指向其中写有“ json”的网址。
John Haugeland

4

到了2020年-没人应该再使用它Net::HTTP了,所有答案似乎都这么说,请使用更高级别的宝石,例如Faraday - Github


就是说,我想做的是围绕HTTP api调用的包装,这种调用称为

rv = Transporter::FaradayHttp[url, options]

因为这允许我伪造HTTP调用而没有其他依赖项,即:

  if InfoSig.env?(:test) && !(url.to_s =~ /localhost/)
    response_body = FakerForTests[url: url, options: options]

  else
    conn = Faraday::Connection.new url, connection_options

伪造者看起来像这样的地方

我知道有HTTP模拟/存根框架,但是至少当我上次进行研究时,它们不允许我有效地验证请求,并且它们仅用于HTTP,而不是用于原始TCP交换,例如,该系统允许我使用所有API通信的统一框架。


假设您只是想将哈希快速快速地转换为json,将json发送到远程主机以测试API并解析对ruby的响应,这可能是最快的方法,而无需涉及其他gem:

JSON.load `curl -H 'Content-Type:application/json' -H 'Accept:application/json' -X POST localhost:3000/simple_api -d '#{message.to_json}'`

希望这不用说,但是不要在生产中使用它。


2
大声笑,为什么所有仇恨者?:)该帖子明确指出其不是用于生产或任何其他严重目的,而是设置JSON api调用以查看服务行为的最快方法
bbozo 2014年

您不能使用NTLM身份验证来执行此操作。因此Net :: HTTP仍然是唯一具有支持该库的库。

1
反对“没有人应该使用Net::HTTP”断言
JellicleCat

由于@bbozo而nobody should be using Net::HTTP any more投票
Patricio

3

这适用于使用JSON对象的ruby 2.4 HTTPS Post,并写出了响应正文。

require 'net/http' #net/https does not have to be required anymore
require 'json'
require 'uri'

uri = URI('https://your.secure-url.com')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
  request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
  request.body = {parameter: 'value'}.to_json
  response = http.request request # Net::HTTPResponse object
  puts "response #{response.body}"
end

2

我喜欢这个名为“ unirest”的轻量级HTTP请求客户端

gem install unirest

用法:

response = Unirest.post "http://httpbin.org/post", 
                        headers:{ "Accept" => "application/json" }, 
                        parameters:{ :age => 23, :foo => "bar" }

response.code # Status code
response.headers # Response headers
response.body # Parsed body
response.raw_body # Unparsed body

1

net / http api可能很难使用。

require "net/http"

uri = URI.parse(uri)

Net::HTTP.new(uri.host, uri.port).start do |client|
  request                 = Net::HTTP::Post.new(uri.path)
  request.body            = "{}"
  request["Content-Type"] = "application/json"
  client.request(request)
end

此代码无效。您需要使用#start初始化Net :: HTTP,如下所示:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler

适用于ruby 2.3.7p456(2018-03-28修订版63024)[universal.x86_64-darwin18]
Moriarty

0
data = {a: {b: [1, 2]}}.to_json
uri = URI 'https://myapp.com/api/v1/resource'
https = Net::HTTP.new uri.host, uri.port
https.use_ssl = true
https.post2 uri.path, data, 'Content-Type' => 'application/json'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.