【问题标题】:Ruby send JSON requestRuby 发送 JSON 请求
【发布时间】:2011-01-02 17:55:13
【问题描述】:

如何在 ruby​​ 中发送 JSON 请求?我有一个 JSON 对象,但我认为我不能只做.send。我必须让 javascript 发送表单吗?

或者我可以在 ruby​​ 中使用 net/http 类吗?

使用 header - content type = json 和 body json 对象?

【问题讨论】:

    标签: ruby json httprequest


    【解决方案1】:

    一个简单的 json POST 请求示例,比 Tom 链接的内容更简单:

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

    【讨论】:

    • 这看起来应该可以,但是 post_form 将参数转换为 ?key=value&key=value 语法。如果您想在请求正文设置为 JSON 字符串的情况下进行 POST,我认为您需要一个不同的解决方案。
    • 这不适用于深度嵌套的 json。第一级以外的任何内容都将成为字符串。
    • 不只是看起来像。有用。这很简单。但对于简单的事情,比如我给出的例子,它工作得很好
    • 这根本不是 JSON 请求。这是一个 urlencoded 身体。没有 JSON。标题甚至说了这么多。这对任何示例都不起作用。
    • 这个答案不正确。它是 mime/multipart 中的 POST,指向其中显示“json”的 url。
    【解决方案2】:

    HTTParty 我认为这让这更容易一些(并且适用于嵌套的 json 等,这在我见过的其他示例中似乎不起作用。

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

    【讨论】:

      【解决方案3】:

      现在是 2020 年 - 没有人应该再使用 Net::HTTP 并且所有答案似乎都这么说,use a more high level gem such as 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
      

      伪装者看起来像this

      我知道有 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}'`
      

      希望这是不言而喻的,但不要在生产中使用它。

      【讨论】:

      • 您不能使用 NTLM 身份验证执行此操作。所以 Net::HTTP 仍然是唯一拥有支持它的库的。
      • 不同意“没有人应该使用Net::HTTP”的断言
      • 因为nobody should be using Net::HTTP any more @bbozo 而被否决
      【解决方案4】:
      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
      

      【讨论】:

      • 我喜欢您的建议,即使用 URI 来处理主机名和端口,否则会非常乏味。但是你忘了在 Post.new(...) 中设置 uri.path:req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
      • 最简单、最干净的响应。这很棒。
      • http.request(req).read_body 读取响应正文。太好了!
      • 我很确定它在 2.4.1 中有所改变,但我的上帝。这种语法很恶心。它知道它有来自 Post.new() 的 URI,那么为什么你必须在 start() 中重新传递值,拆分。总的。难怪 ruby​​ 中有这么多其他包处理 http。
      【解决方案5】:
      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
      

      【讨论】:

      • 应该指定哪个异常
      • 对于 https 请求只需添加:http.use_ssl = true。
      【解决方案6】:

      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|
      • 适用于 ruby​​ 2.3.7p456(2018-03-28 修订版 63024)[universal.x86_64-darwin18]
      【解决方案7】:

      我喜欢这个名为 `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
      

      【讨论】:

        【解决方案8】:
        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'
        

        【讨论】:

          【解决方案9】:

          现实生活中的例子,通过NetHttps通知Airbrake API about new deployment

          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)
          

          注意事项:

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

          【讨论】:

          • ...但老实说这很酷,但在现实生活中我只会使用 HTTParty stackoverflow.com/a/14491995/473040 :) ...尤其是如果您正在处理 https 处理
          • 需要 uri 是没用的,因为 net/http 已经需要它了
          • @equivalent8:“在现实生活中我只会使用 HTTParty”——也就是说,除非你正在构建一个精简的 gem,或者不想要另一个依赖项。 :)
          • @SergioTulentsev 同意...除非您正在构建 gem/lib(或基于 Ruby 的微服务),而您不想引入不必要的依赖项;)
          【解决方案10】:

          这适用于带有 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
          

          【讨论】:

            猜你喜欢
            • 2012-08-08
            • 1970-01-01
            • 2016-02-01
            • 1970-01-01
            • 2014-03-29
            • 2018-02-16
            • 2018-02-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多