如何在 ruby​​ 中通过 SSL 调用 HTTP POST 方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10919287/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 05:10:58  来源:igfitidea点击:

How to invoke HTTP POST method over SSL in ruby?

rubysslcurlhttps

提问by NielMalhotra

So here's the request using curl:

所以这是使用 curl 的请求:

curl -XPOST -H content-type:application/json -d "{\"credentials\":{\"username\":\"username\",\"key\":\"key\"}}" https://auth.api.rackspacecloud.com/v1.1/auth

I've been trying to make this same request using ruby, but I can't seem to get it to work.

我一直在尝试使用 ruby​​ 提出同样的请求,但我似乎无法让它工作。

I tried a couple of libraries also, but I can't get it to work. Here's what I have so far:

我也尝试了几个图书馆,但我无法让它工作。这是我到目前为止所拥有的:

uri = URI.parse("https://auth.api.rackspacecloud.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new("/v1.1/auth")
request.set_form_data({'credentials' => {'username' => 'username', 'key' => 'key'}})
response = http.request(request)

I get a 415 unsupported media type error.

我收到 415 不受支持的媒体类型错误。

回答by Eugene

You are close, but not quite there. Try something like this instead:

你很近,但不完全在那里。试试这样的:

uri = URI.parse("https://auth.api.rackspacecloud.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new("/v1.1/auth")
request.add_field('Content-Type', 'application/json')
request.body = {'credentials' => {'username' => 'username', 'key' => 'key'}}.to_json
response = http.request(request)

This will set the Content-Type header as well as post the JSON in the body, rather than in the form data as your code had it. With the sample credentials, it still fails, but I suspect it should work with real data in there.

这将设置 Content-Type 标头并在正文中发布 JSON,而不是像您的代码那样在表单数据中发布。使用示例凭据,它仍然失败,但我怀疑它应该可以使用其中的真实数据。

回答by Jason Lewis

There's a very good explanation of how to make a JSON POST request with Net::HTTP at this link.

关于如何使用 Net::HTTP在此链接上发出 JSON POST 请求,有一个很好的解释。

I would recommend using a library like HTTParty. It's well-documented, you can just set up your class like so:

我建议使用像HTTParty这样的库。它有据可查,您可以像这样设置您的课程:

class RackSpaceClient
  include HTTParty

  base_uri "https://auth.api.rackspacecloud.com/"
  format :json
  headers 'Accept' => 'application/json'

  #methods to do whatever

end

It looks like the main difference between the Ruby code you placed there, and the curl request, is that the curl request is POSTing JSON (content-type application/json) to the endpoint, whereas request.set_form_datais going to send a form in the body of the POST request (content-type application/x-www-form-urlencoded). You have to make sure the content going both ways is of type application/json.

看起来您放置在那里的 Ruby 代码与 curl 请求之间的主要区别在于 curl 请求将 JSON(内容类型应用程序/json)发送到端点,而request.set_form_data将在POST 请求(内容类型应用程序/x-www-form-urlencoded)。你必须确保双向的内容是 application/json 类型。

回答by Noamsh

Another example:

另一个例子:

#!/usr/bin/ruby

require 'net/http'
require 'json'
require 'uri'

full_url = "http://" + options[:artifactory_url] + "/" + "api/build/promote/" + options[:build]

puts "Artifactory url: #{full_url}"

data = {
    status: "staged",
    comment: "Tested on all target platforms.",
    ciUser: "builder",
    #timestamp: "ISO8601",
    dryRun: false,
    targetRepo: "#{options[:target]}",
    copy: true,
    artifacts: true,
    dependencies: false,
    failFast: true,
}

uri = URI.parse(full_url)
headers = {'Content-Type' => "application/json", 'Accept-Encoding'=> "gzip,deflate",'Accept' => "application/json" }
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri, headers)
request.basic_auth(options[:user], options[:password])
request.body = data.to_json
response = http.request(request)

puts response.code
puts response.body

回答by Kashyap

All others are too long here is a ONE LINER:

所有其他的都太长了,这里是ONE LINER

Net::HTTP.start('auth.api.rackspacecloud.com', :use_ssl => true).post(
      '/v1.1/auth', {:credentials => {:username => "username",:key => "key"}}.to_json,
      initheader={'Content-Type' => 'application/json'}
    )

* to_jsonneeds require 'json'

*to_json需要require 'json'



OR if you want to

或者如果你想

  • NOTverify the hosts
  • be more readable
  • ensure the connection is closed once you're done
  • 验证主机
  • 更具可读性
  • 完成后确保连接关闭

then:

然后:

ssl_opts={:use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE}
Net::HTTP.start('auth.api.rackspacecloud.com', ssl_opts) { |secure_connection|
  secure_connection.post(
      '/v1.1/auth', {:credentials => {:username => "username",:key => "key"}}.to_json,
      initheader={'Content-Type' => 'application/json'}
    )
}

In case it's tough to remember what params go where:

以防万一很难记住参数去哪里:

  • SSL options are per connection so you specify them while opening the connection.
  • You can reuse the connection for multiple REST calls to same base url. Think of thread safety of course.
  • Header is a "request header" and hence specified per request. I.e. in calls to get/post/patch/....
  • HTTP.start(): Creates a new Net::HTTP object, then additionally opens the TCP connection and HTTP session.
  • HTTP.new(): Creates a new Net::HTTP object without opening a TCP connection or HTTP session.
  • SSL 选项是针对每个连接的,因此您可以在打开连接时指定它们。
  • 您可以为多个 REST 调用重用连接到相同的基本 url。当然要考虑线程安全。
  • 标头是“请求标头”,因此按请求指定。即调用get/ post/ patch/ ...
  • HTTP.start(): 创建一个新的 Net::HTTP 对象,然后另外打开 TCP 连接和 HTTP 会话。
  • HTTP.new():在不打开 TCP 连接或 HTTP 会话的情况下创建一个新的 Net::HTTP 对象。