Faraday: La validación de URI falla cuando contiene caracteres reservados

Creado en 4 dic. 2020  ·  3Comentarios  ·  Fuente: lostisland/faraday

Información básica

  • Versión de Faraday: 1.1.0
  • Versión de Ruby: 2.7.1

Descripcion del problema

Uno de los proveedores de servicios que estoy usando tiene URL como esta: https://service.com/service:search . Así es como configuramos Faraday:

class Provider::Client
 ...
 delegate :post, :patch, :delete, :put, to: :client

 def client
  Faraday.new(url: 'https://service.com/') do |faraday|
    faraday.headers = headers.merge(content_type: content_type)
    faraday.response(:json, content_type: CONTENT_TYPE)
    faraday.basic_auth(USER, PASSWORD)
    faraday.adapter(Faraday.default_adapter)
  end
 end
end

y cuando lo invoco

data = Provider::Client.post(
  "service:search?limit=#{LIMIT}&offset=#{offset}", search_params
)

pero cuando hago esto con la URL en cuestión, obtengo esto:

URI::InvalidURIError: query conflicts with opaque
from /Users/luiz/.rbenv/versions/2.7.1/lib/ruby/2.7.0/uri/generic.rb:832:in `query='

Supongo que fue algo relacionado con el adaptador net / http, ya que es el adaptador predeterminado, así que hice la misma llamada manualmente

require "uri"
require "net/http"

url = URI("https://service.com/service:search?limit=50&offset=400")

https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Accept"] = "custom_header"
request["Authorization"] = "Basic xxx="
request["Content-Type"] = "application/json"
request.body = "long_json"
response = https.request(request)

puts response.read_body

y esto realmente funciona, así que sospecho que algo en Faraday está validando esta URL de una manera diferente a net / http

bug good first issue

Comentario más útil

@luizkowalski perfecto, sí, eso es exactamente lo que quise decir con

Sin embargo, esto no funciona en todos los casos, ya que es posible que deba agregar una ruta relativa a la base que no puede comenzar con /.

Como faraday asume que la URL proporcionada es absoluta si comienza con / y elimina la ruta proporcionada a la base.
Me alegro de que ya haya encontrado la solución alternativa, pero aún así debería solucionarse correctamente para que ya no sea necesaria una solución alternativa

Todos 3 comentarios

Hola @luizkowalski , la excepción proviene de URI y se genera en las primeras líneas del método query= :

def query=(v)
  return <strong i="9">@query</strong> = nil unless v
  raise InvalidURIError, "query conflicts with opaque" if <strong i="10">@opaque</strong>
  ...
end

Faraday hace algo de magia interna en la URL de la solicitud dividiéndola y recombinándola para ayudar con algunas transformaciones comunes, y supongo que en algún momento puede causar que @opaque se establezca gracias a la presencia de : en la URL.
He rastreado el problema hasta esta línea: https://github.com/lostisland/faraday/blob/c26df87b8653db4f270e3bcdc7a15bcdd2dd5cae/lib/faraday/connection.rb#L525
Usando su código de ejemplo, base sería #<URI::HTTPS https://service.com/> y url sería service:search?limit=50&offset=400 .
Ahora, curiosamente, si el segundo parámetro del método + para URI contiene un : , ¡parece que el resultado es bastante inesperado!

2.7.1 > url
 => "service:search?limit=50&offset=400" 
2.7.1 > base
 => #<URI::HTTPS https://service.com/> 
2.7.1 > base + url
 => #<URI::Generic service:search?limit=50&offset=400>

Por alguna razón, base se elimina y solo queda la URL.
La solución es bastante fácil en este caso, basta con anteponer un / a la URL y las cosas funcionan como se esperaba:

data = Provider::Client.post(
  "/service:search?limit=#{LIMIT}&offset=#{offset}", search_params
)

Sin embargo, esto no funciona en todos los casos, ya que es posible que deba agregar una ruta relativa a base que no puede comenzar con / .
Por favor, intente esto anteponiendo el / y avíseme si funciona, pero dejaré este problema abierto para echar un vistazo y encontrar una posible manera de arreglar esa línea de código en Faraday para que funciona en este caso.
Si quieres probarlo tú mismo, felizmente revisaría un PR 😃

@iMacTia funcionó ahora. La URL base es: https://service.com/api . Cuando agregué / a service:search recibí un error y noté que /api había desaparecido de la URL base, así que agregué /api/service:search y ahora está bien

@luizkowalski perfecto, sí, eso es exactamente lo que quise decir con

Sin embargo, esto no funciona en todos los casos, ya que es posible que deba agregar una ruta relativa a la base que no puede comenzar con /.

Como faraday asume que la URL proporcionada es absoluta si comienza con / y elimina la ruta proporcionada a la base.
Me alegro de que ya haya encontrado la solución alternativa, pero aún así debería solucionarse correctamente para que ya no sea necesaria una solución alternativa

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

t3hk0d3 picture t3hk0d3  ·  3Comentarios

jordansissel picture jordansissel  ·  5Comentarios

Lewiscowles1986 picture Lewiscowles1986  ·  4Comentarios

mattmill30 picture mattmill30  ·  4Comentarios

yusefu picture yusefu  ·  3Comentarios