问题
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:
- Install the
faraday
andsocksify
gems 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
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