A list of proxies becomes useful only when each attempt creates a client configured for that endpoint. For a GET through unauthenticated HTTP proxies, Net::HTTP can be used like this:

require 'net/http'

uri = URI('https://www.example.com/status')
proxies = ['http://proxy-a.example:8080',
           'http://proxy-b.example:8080']

proxies.each do |value|
  proxy = URI(value)
  http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port)
  http.use_ssl = uri.scheme == 'https'
  http.open_timeout = 5
  http.read_timeout = 10
  begin
    response = http.get(uri.request_uri)
    puts "#{proxy.host}:#{proxy.port} #{response.code}"
    break if response.is_a?(Net::HTTPSuccess)
  rescue Net::OpenTimeout, Net::ReadTimeout, SocketError, SystemCallError, IOError => error
    warn "#{proxy.host}:#{proxy.port} #{error.class}"
  end
end

The fourth argument selects the proxy port; uri.host and uri.port still identify the destination. Populate the two example entries from the HTTP proxy list when checking an allowed public URL through unauthenticated HTTP endpoints. request_uri preserves its path and query. The example handles ordinary connection and read failures and records an HTTP status when one arrives.

Here any 2xx response ends the search. If your operation expects another result, define that criterion explicitly. A redirect does not automatically prove that the desired page was retrieved.

Keep automatic repetition appropriate to the method. A POST that times out after its body was sent might already have changed the remote application; trying it again through another proxy can repeat that effect. The GET example avoids promising safe replay of arbitrary transactions.

Allakkat attuumassuteqartut