Ruby gửi yêu cầu JSON


86

Làm cách nào để gửi yêu cầu JSON bằng ruby? Tôi có một đối tượng JSON nhưng tôi không nghĩ mình có thể làm được .send. Tôi có phải có javascript để gửi biểu mẫu không?

Hoặc tôi có thể sử dụng lớp net / http trong ruby ​​không?

Với header - content type = json và nội dung là đối tượng json?

Câu trả lời:


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
Tôi thích đề xuất của bạn là sử dụng URI để xử lý tên máy và cổng, nếu không thì khá tẻ nhạt. Nhưng bạn quên đặt uri.path trong Post.new (...):req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
ArnauOrriols

1
Phản hồi đơn giản nhất, rõ ràng nhất. Điều đó thật tuyệt.
joelc

http.request(req).read_bodyđể đọc nội dung phản hồi. Tuyệt quá!
iGian

1
Tôi khá chắc rằng nó đã thay đổi trong 2.4.1 nhưng chúa ơi. Cú pháp đó thật thô thiển. Nó biết nó có URI từ Post.new (), vậy tại sao bạn phải repass các giá trị, chia nhỏ, trong start (). Tổng. Không có gì ngạc nhiên khi có rất nhiều gói khác trong ruby ​​giao dịch với http.
Rambatino

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

Ngoại lệ nào nên được chỉ định
Mio

7
Đối với các yêu cầu https, chỉ cần thêm: http.use_ssl = true.
Kỹ năng M2

17

Tôi nghĩ HTTParty làm cho điều này dễ dàng hơn một chút (và hoạt động với json lồng nhau, v.v., điều này dường như không hoạt động trong các ví dụ khác mà tôi đã thấy.

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

6

ví dụ trong cuộc sống thực, thông báo cho API Airbrake về việc triển khai mới qua NetHttps

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)

Ghi chú:

trong trường hợp bạn thực hiện xác thực thông qua tiêu đề bộ tiêu đề Ủy quyền req['Authorization'] = "Token xxxxxxxxxxxx" hoặc http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html


... nhưng thành thật mà nói thì điều này thật tuyệt và tất cả nhưng trong thực tế, tôi sẽ chỉ sử dụng HTTParty stackoverflow.com/a/14491995/473040 :) ... đặc biệt nếu bạn đang xử lý https
tương đương

đòi hỏi uri là vô ích vì nó đã được yêu cầu của net / http
noraj

@ tương đương8: "trong cuộc sống thực, tôi sẽ chỉ sử dụng HTTParty" - nghĩa là, trừ khi bạn đang xây dựng một viên ngọc tinh gọn, hoặc nếu không thì không muốn có một sự phụ thuộc khác. :)
Sergio Tishedsev

@SergioTishedsev đồng ý ... trừ khi bạn đang xây dựng gem / lib (hoặc microservice dựa trên Ruby), nơi bạn không muốn giới thiệu các phụ thuộc không cần thiết;)
tương đương

4

Một ví dụ đơn giản về yêu cầu POST của json cho những người cần nó thậm chí còn đơn giản hơn những gì Tom đang liên kết đến:

require 'net/http'

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

19
Điều này có vẻ như nó sẽ hoạt động, nhưng post_form dịch các tham số thành cú pháp? Key = value & key = value. Nếu bạn muốn thực hiện POST với phần thân yêu cầu được đặt thành chuỗi JSON, tôi nghĩ bạn cần một giải pháp khác.
Ben Gotow

Điều này không hoạt động với json lồng nhau sâu. Bất cứ thứ gì vượt quá mức đầu tiên đều trở thành một chuỗi.
neoneye

Không chỉ giống như vậy. Nó hoạt động. Nó đơn giản chắc chắn. nhưng đối với những điều đơn giản như ví dụ tôi đã đưa nó hoạt động tốt
Christoffer

4
Về cơ bản, đây không phải là một yêu cầu JSON. Đây là một cơ thể được mã hóa. Không có JSON. Tiêu đề thậm chí còn nói lên nhiều điều. Điều này không hoạt động với bất kỳ ví dụ nào.
raylu

4
Câu trả lời này không chính xác. Đó là BÀI ĐĂNG bằng mime / nhiều phần, đến một url có ghi "json" trong đó.
John Haugeland 21/12/16

4

Đó là năm 2020 - không ai nên sử dụng Net::HTTPnữa và tất cả các câu trả lời dường như đang nói như vậy, hãy sử dụng một viên ngọc cấp cao hơn như Faraday - Github


Điều đó nói rằng, những gì tôi muốn làm là bao bọc xung quanh lệnh gọi HTTP api, một cái gì đó được gọi là

rv = Transporter::FaradayHttp[url, options]

bởi vì điều này cho phép tôi giả mạo các cuộc gọi HTTP mà không có phụ thuộc bổ sung, tức là:

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

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

Nơi mà faker trông giống như thế này

Tôi biết có các khuôn khổ bắt chước / sơ khai HTTP, nhưng ít nhất khi tôi nghiên cứu lần trước, chúng không cho phép tôi xác thực các yêu cầu một cách hiệu quả và chúng chỉ dành cho HTTP, không phải ví dụ cho các trao đổi TCP thô, hệ thống này cho phép tôi có khung thống nhất cho tất cả các giao tiếp API.


Giả sử bạn chỉ muốn chuyển đổi một cách nhanh chóng và bẩn thỉu một băm thành json, hãy gửi json đến một máy chủ từ xa để kiểm tra API và phân tích cú pháp phản hồi với ruby, đây có lẽ là cách nhanh nhất mà không cần thêm đá quý:

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

Hy vọng rằng điều này không cần phải nói, nhưng không sử dụng điều này trong sản xuất.


2
Lol, tại sao tất cả những kẻ thù ghét? :) Bài đăng nêu rõ không phải vì mục đích sản xuất hay bất kỳ mục đích nghiêm trọng nào khác, mà là cách nhanh nhất để thiết lập lệnh gọi JSON api để xem cách một dịch vụ hoạt động
bbozo

Bạn không thể thực hiện việc này bằng xác thực NTLM. Vì vậy, Net :: HTTP vẫn là cái duy nhất có thư viện hỗ trợ nó.
Rhuan

1
Không đồng ý với Net::HTTPkhẳng định 'không ai nên sử dụng '
JellicleCat

nobody should be using Net::HTTP any moreBị phản đối vì @bbozo
Patricio Sard

3

Điều này hoạt động trên ruby ​​2.4 HTTPS Post với đối tượng JSON và nội dung phản hồi được viết ra.

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

Tôi thích ứng dụng khách yêu cầu http trọng lượng nhẹ này có tên là ʻunirest '

gem install unirest

sử dụng:

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

Mạng / http api có thể khó sử dụng.

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

Mã này không hoạt động. Bạn cần khởi tạo Net :: HTTP với #start như vậy:Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |client|
Tyler

Làm việc với ruby ​​2.3.7p456 (2018-03-28 bản sửa đổi 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'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.