Faraday: Проверка URI не выполняется, если он содержит зарезервированные символы

Созданный на 4 дек. 2020  ·  3Комментарии  ·  Источник: lostisland/faraday

Основная информация

  • Версия Фарадея: 1.1.0
  • Версия Ruby: 2.7.1

Описание проблемы

У одного из поставщиков услуг, которого я использую, есть такие URL: https://service.com/service:search . Вот как мы настраиваем Фарадея:

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

и когда я вызываю это

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

но когда я делаю это с указанным URL, я получаю следующее:

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

Я предполагаю, что это было связано с адаптером net / http, поскольку это адаптер по умолчанию, поэтому я сделал тот же вызов вручную

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

и это действительно работает, поэтому я подозреваю, что что-то в Фарадея проверяет этот URL иначе, чем net / http

bug good first issue

Самый полезный комментарий

@luizkowalski идеально, да, именно это я имел в виду

Однако это работает не во всех случаях, так как вам может потребоваться добавить относительный путь к базе, который не может начинаться с /.

Как предполагает Фарадей, предоставленный URL-адрес является абсолютным, если он начинается с / и удаляет путь, предоставленный к базе.
Рад, что вы уже нашли обходной путь, но это все равно нужно исправить, чтобы обходной путь больше не нужен

Все 3 Комментарий

Привет, @luizkowalski , исключение исходит от URI и возникает в первых строках метода 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

Фарадей совершает некоторую внутреннюю магию с URL-адресом запроса, разделяя и рекомбинируя его, чтобы помочь с некоторыми общими преобразованиями, и я предполагаю, что в какой-то момент это может привести к установке @opaque благодаря наличию : в URL.
Я проследил проблему до этой строки: https://github.com/lostisland/faraday/blob/c26df87b8653db4f270e3bcdc7a15bcdd2dd5cae/lib/faraday/connection.rb#L525
Используя ваш пример кода, base будет #<URI::HTTPS https://service.com/> а url будет service:search?limit=50&offset=400 .
Что интересно, если второй параметр метода + для URI содержит : , результат кажется весьма неожиданным!

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>

По какой-то причине base удаляется, и остается только URL-адрес.
В этом случае исправить довольно просто, достаточно просто добавить / к URL-адресу, и все заработает, как ожидалось:

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

Однако это работает не во всех случаях, поскольку вам может потребоваться добавить относительный путь к base который не может начинаться с / .
Пожалуйста, попробуйте это, добавив / и дайте мне знать, работает ли это, но я оставлю эту проблему открытой, чтобы посмотреть и найти возможный способ исправить эту строку кода в Фарадея, чтобы она работает в этом случае.
Если вы хотите попробовать сами, я с удовольствием пересмотрю PR 😃

@iMacTia теперь https://service.com/api . Когда я добавил / в service:search я получил сообщение об ошибке и заметил, что /api исчез из базового URL, поэтому я добавил /api/service:search и теперь все в порядке.

@luizkowalski идеально, да, именно это я имел в виду

Однако это работает не во всех случаях, так как вам может потребоваться добавить относительный путь к базе, который не может начинаться с /.

Как предполагает Фарадей, предоставленный URL-адрес является абсолютным, если он начинается с / и удаляет путь, предоставленный к базе.
Рад, что вы уже нашли обходной путь, но это все равно нужно исправить, чтобы обходной путь больше не нужен

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

olleolleolle picture olleolleolle  ·  5Комментарии

Lewiscowles1986 picture Lewiscowles1986  ·  4Комментарии

iMacTia picture iMacTia  ·  3Комментарии

jeffb-stell picture jeffb-stell  ·  5Комментарии

yusefu picture yusefu  ·  3Комментарии