Faraday: La validation d'URI échoue lorsqu'elle contient des caractères réservés

Créé le 4 déc. 2020  ·  3Commentaires  ·  Source: lostisland/faraday

Informations de base

  • Version Faraday : 1.1.0
  • Version Rubis : 2.7.1

Description du problème

L'un des fournisseurs de services que j'utilise a des URL comme celle-ci : https://service.com/service:search . Voici comment nous avons configuré 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

et quand je l'invoque

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

mais quand je fais cela avec l'URL en question, j'obtiens ceci :

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='

Je suppose que c'était quelque chose lié à l'adaptateur net/http car c'est l'adaptateur par défaut donc j'ai fait le même appel manuellement

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

et cela fonctionne réellement, donc je soupçonne que quelque chose dans Faraday valide cette URL d'une manière différente de net/http

bug good first issue

Commentaire le plus utile

@luizkowalski parfait, oui c'est exactement ce que je voulais dire avec

Cependant, cela ne fonctionne pas dans tous les cas car vous devrez peut-être ajouter un chemin relatif à la base qui ne peut pas commencer par /.

Comme faraday suppose que l'URL fournie est absolue si elle commence par / et a supprimé le chemin fourni à la base.
Heureux que vous ayez déjà trouvé la solution de contournement, mais cela devrait toujours être corrigé correctement afin que la solution de contournement ne soit plus nécessaire

Tous les 3 commentaires

Salut @luizkowalski , l'exception vient de URI et est levée dans les premières lignes de la méthode 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 fait de la magie interne sur l'URL de demande en la divisant et en la recombinant pour aider à certaines transformations courantes, et je suppose qu'à un moment donné, cela peut entraîner la définition du @opaque grâce à la présence du : dans l'URL.
J'ai retracé le problème jusqu'à cette ligne : https://github.com/lostisland/faraday/blob/c26df87b8653db4f270e3bcdc7a15bcdd2dd5cae/lib/faraday/connection.rb#L525
En utilisant votre exemple de code, base serait #<URI::HTTPS https://service.com/> et url serait service:search?limit=50&offset=400 .
Maintenant, assez intéressant, si le deuxième paramètre de la méthode + pour l'URI contient un : , il semble que le résultat soit assez inattendu !

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>

Pour une raison quelconque, le base est supprimé et seule l'URL est laissée.
Le correctif est assez simple dans ce cas, il suffit d'ajouter un / à l'URL et les choses fonctionnent comme prévu :

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

Cependant, cela ne fonctionne pas dans tous les cas car vous devrez peut-être ajouter un chemin relatif au base qui ne peut pas commencer par / .
Veuillez essayer ceci en ajoutant le / et laissez-moi savoir si cela fonctionne, mais je laisserai ce problème ouvert pour jeter un œil et trouver un moyen possible de corriger cette ligne de code dans Faraday afin qu'elle fonctionne dans ce cas.
Si vous voulez essayer vous-même, je serais ravi de revoir un PR

@iMacTia cela a fonctionné maintenant. L'URL de base est : https://service.com/api . Lorsque j'ai ajouté le / à service:search j'ai eu une erreur et j'ai remarqué que le /api avait disparu de l'URL de base, j'ai donc ajouté /api/service:search et maintenant tout va bien

@luizkowalski parfait, oui c'est exactement ce que je voulais dire avec

Cependant, cela ne fonctionne pas dans tous les cas car vous devrez peut-être ajouter un chemin relatif à la base qui ne peut pas commencer par /.

Comme faraday suppose que l'URL fournie est absolue si elle commence par / et a supprimé le chemin fourni à la base.
Heureux que vous ayez déjà trouvé la solution de contournement, mais cela devrait toujours être corrigé correctement afin que la solution de contournement ne soit plus nécessaire

Cette page vous a été utile?
0 / 5 - 0 notes