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
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
Comentario más útil
@luizkowalski perfecto, sí, eso es exactamente lo que quise decir 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