converting a curl call to a faraday request

眉间皱痕 提交于 2019-12-23 21:13:30

问题


I have the following curl request -

`curl --socks5 #{proxy} --connect-timeout 10 -H "Accept: application/json" #{url}`

I want to write a faraday request instead of a curl call. I am doing this -

faraday =  Faraday.new("#{url}", ssl:{verify: false} do |f|
    f.proxy "#{proxy}"
end
faraday.get

I am getting a reponse but the response has no body or headers. Following is the response -

#<Faraday::Response:0x0056075d353ad0 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @url=#<URI::HTTP:0x0056075d358328 URL:main_url> @request=#<Faraday::RequestOptions proxy=#<Faraday::ProxyOptions uri=#<URI::HTTP:0x0056075dce69d0 URL:proxy_url>>> @request_headers={"User-Agent"=>"Faraday v0.9.2"} @ssl=#<Faraday::SSLOptions (empty)> @response=#<Faraday::Response:0x0056075d353ad0 ...>>>

What am I doing wrong here?


回答1:


The hardest issue with the conversion to Faraday is that you need to use a SOCKS5 proxy. Faraday does not support SOCKS proxies (there is an open pull-request for this).

The only way around this is to monkey-patch Faraday to use the socksify gem which adds support for SOCKS proxies to Net::HTTP (the default Faraday network adapter). The procedure is nicely described in this gist and I mostly copy-paste a slightly altered version of it here.

Basically you need to follow these steps:

  1. Install the faraday and socksify gems
  2. Monkey-patch Faraday to support SOCKS. Put this code into a Rails initializer. Note that the patch only applies if you don't need to authenticate to the SOCKS proxy (as your curl command suggests). If you need proxy authentication, see the gist for a patch version supporting that. The patch is as follows:

    class Faraday::Adapter::NetHttp
      def net_http_connection(env)
        if proxy = env[:request][:proxy]
          if proxy[:socks]
            Net::HTTP::SOCKSProxy(proxy[:uri].host, proxy[:uri].port)
          else
            Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:uri].user, proxy[:uri].password)
          end
        else
            Net::HTTP
        end.new(env[:url].host, env[:url].port)
      end
    end
    
  3. Create the request. I noticed you are probably trying to make a HTTPS request so I took this into account, as well as the timeouts you have in the curl parameters:

    PROXY_OPTS = {
            uri:  URI.parse('https://proxy_url:1080'),
            socks: true  
        }
    
    SSL_OPTS = { verify: false }
    
    connection = Faraday.new(url: "https://example.com",
                             ssl: SSL_OPTS,
                             request: { proxy: PROXY_OPTS }) do |faraday|
      faraday.options.timeout = 10           # open/read timeout in seconds
      faraday.options.open_timeout = 10      # connection open timeout in seconds
      faraday.response :logger               # log debug info
      faraday.adapter  :net_http             # use the Net:HTTP adapter
    
      faraday.headers['Accept'] = 'application/json'  # your custom headers
    end
    
    response = connection.get
    response.body
    

Finally, please note that ignoring peer verification (verify: false in the SSL options) is insecure! You should instead properly configure Faraday to use a certificate store to verify peer certificates against. This is fully documented here.




回答2:


This is how I use faraday for a post request to get an access token from Microsoft Exchange API for example.

url = "https://login.microsoftonline.com/#{ENV['TENANT']}/oauth2/token"

conn = Faraday.new url: url do |faraday|
  faraday.request  :url_encoded             # form-encode POST params
  faraday.response :logger                  # log requests to STDOUT
  faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
end

response = conn.post do |req|
  req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
  req.body = {
    client_id: URI::encode(ENV['CLIENT_ID']),
    client_secret: URI::encode(ENV['CLIENT_SECRET']),
    resource: URI::encode('https://graph.microsoft.com'),
    grant_type: URI::encode('client_credentials'),
  }
  Rails.logger.info "Body #{req.body.inspect}"
end

if response.status.to_i == 200
  response_body = ActiveSupport::JSON.decode(response.body)
  return response_body['access_token']
else
  return false
end

Hope it helps.



来源:https://stackoverflow.com/questions/36434141/converting-a-curl-call-to-a-faraday-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!