Как я могу получить доступ к необработанному телу запроса в сценариях ruby ​​CGI? - PullRequest
0 голосов
/ 16 сентября 2018

В скрипте ruby, который я запускаю как CGI-программу, мне нужно получить доступ к телу HTTP-запроса POST.Тело запроса содержит данные JSON:

{"data":"a"}

Я хочу взять все тело и проанализировать его с помощью JSON.parse для его обработки.Какой канонический способ сделать это?В Ruby docs не упоминается тело запроса.

Я нашел только подсказку в сообщении в блоге , которое

CGI пытаетсячтобы проанализировать тело запроса как параметры формы, чтобы блоб JSON неуклюже оказался единственным ключом параметра.

Этот подход работает

puts cgi.params.keys.first # prints {"data":"a"}

, но не работает каккак только значение для data является строкой в ​​кодировке base64, содержащей = для заполнения: использование этого тела

{"data":"a="}

приводит к следующему выводу (символы отсутствуют в конце):

puts cgi.params.keys.first # prints {"data":"a

Как правильно решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Очевидно, в Ruby нет простого решения для этого.

Но есть два способа добиться этого.

  1. Переопределить CGI::parse(params) метод. Этот метод в модуле CGI отвечает за синтаксический анализ параметров POST и GET в хэше params. Вы можете переопределить этот метод в своем коде так, чтобы он добавил дополнительный параметр с именем RAW_DATA в params хэш.

    def CGI::parse(query)
       params = {}
       query.split(/[&;]/).each do |pairs |
       key, value = pairs.split('=', 2).collect {
         | v | CGI::unescape(v)
        }
    
       next unless key
    
       params[key] || = []
       params[key].push(value) if value
     end
    
     #Add RAW_DATA to params
     params[:RAW_DATA] = query
    
     params.default = [].freeze
     params
    end
    
  2. Используйте $stdin.read() перед созданием экземпляра CGI. Но это может помешать вам использовать другие функции CGI.

    Таким образом, вы можете временно заменить $ stdin объектом StringIO.

    require 'cgi'
    require 'stringio'
    
    raw_data  = $stdin.read()
    
    real_stdin = $stdin
    $stdin     = StringIO.new(raw_data)
    STDIN      = $stdin
    
    cgi = CGI.new
    
    #Your CGI code here
    
    #........
    
    $stdin = real_stdin
    STDIN  = $stdin
    
0 голосов
/ 16 сентября 2018

Как вы, возможно, уже знаете, когда параметры и их значения кодируются с помощью urlencoded, они разделяются =: name=Theo&language=ruby и т. Д.

Именно поэтому имя первого параметра останавливается на символе перед =. Подход с использованием первого ключа, описанный в этом сообщении в блоге, не совсем надежен.

Вместо этого в CGI-скрипте вы можете прочитать тело запроса непосредственно из stdin, например:

request_body = $stdin.read

Обратите внимание, что когда вы создаете экземпляр объекта CGI, он будет читать все со стандартного ввода и пытаться разобрать его в хэш params.

Это означает, что если вы все еще хотите использовать библиотеку cgi для построения своего ответа, вам нужно прочитать из stdin ранее в коде, до создания объекта CGI. например,

# minimal example that just outputs the request body
require 'cgi'

request_body = $stdin.read

cgi = CGI.new

cgi.out("status" => "OK", "type" => "text/plain", "connection" => "close") do
  request_body
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...