在远程主机上,我有一个bash脚本将一个简单的gzip yaml文件发送到我的ruby sinatra端点:

#!/bin/bash

/bin/gzip -c /tmp/test.yaml > /tmp/test.gz

curl -i <hostname>:<port>/last_run_report -H "Content-Type: application/xml" -H "Content-Encoding: gzip" --data-binary @/tmp/test.gz

我的Ruby应用程序示例是:
require 'sinatra'
require 'zlib'
require 'stringio'

set :port, <port>
set :bind, "<ip>"

post '/last_run_report' do
  sio = StringIO.new(request.body.to_s)
  gz = Zlib::GzipReader.new(sio).read
  test_yaml = YAML.load(gz)
end

这会导致以下错误:
Zlib::GzipFile::Error: not in gzip format

如果我需要'base64'并将端点定义更改为:
post '/last_run_report' do
  raw = Base64.decode64(request.body)
  sio = StringIO.new(raw)
  gz = Zlib::GzipReader.new(sio).read
  test_yaml = YAML.load(gz)
end

我得到以下错误:
NoMethodError: undefined method `unpack1' for #<StringIO:0x000055713e2d51b8>

我不知道我是发送错误的数据还是读取错误的数据请帮忙。

最佳答案

假设YAML样本如下:

martin:
    name: Martin D'vloper
    job: Developer
    skill: Elite

你不需要所有多余的东西。StringIO已经是一个request.body实例,因此将其转换为字符串,然后将其转换为StringIO是不必要的:
require 'sinatra'
require 'zlib'

post '/last_run_report' do
  gz = Zlib::GzipReader.new(request.body).read
  puts YAML.load(gz)
end

现在提出请求:
curl -i localhost:4567/last_run_report -H "Content-Type: application/xml" -H "Content-Encoding: gzip" --data-binary @test.gz

并查看sinatra输出:
== Sinatra (v2.0.4) has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
{"martin"=>{"name"=>"Martin D'vloper", "job"=>"Developer", "skill"=>"Elite"}}
::1 - - [14/Jan/2019:23:24:28 -0700] "POST /last_run_report HTTP/1.1" 200 - 0.0048

注意StringIO已将puts写入控制台。
我应该指出,在您的示例中,以下代码的工作方式与您预期的不同:
sio = StringIO.new(request.body.to_s)

您希望能够致电{"martin"=>{"name"=>"Martin D'vloper", "job"=>"Developer", "skill"=>"Elite"}}并获得如下信息:
\x1F\x8B\b\b\xA7z=\\\x00\x03test.yaml\x00SVp\xCCSH\xCD-\xC8\xC9\xAFLMU(JM\xCE/J\xE1\xCAM,*\xC9\xCC\xB3\xE2R\x00\x82\xBC\xC4\xDCT+\x05_\xB0\x88\x82\x8BzYN~Aj\x11X&+?\xC9J\xC1%\xB5,\x15!T\x9C\x9D\x99\x93c\xA5\xE0\x9A\x93Y\x92\n\x00\xFC\xA0\x83yZ\x00\x00\x00

实际上你得到的是:
#<StringIO:0x00007ffd8184bdf0>

注意,这是文本字符串“sio.read”,而不是对#<StringIO:0x00007ffd8184bdf0>对象的引用,因为这是在对StringIO对象(如.to_s调用StringIO时返回的内容,因此对request.body的任何后续调用(在对sio.read的调用中隐含)都将返回该文本字符串,而不会返回您希望它返回的gzip数据,这将导致错误Zlib::GzipReader.new
当您想返回Zlib::GzipFile::Error: not in gzip format的字符串表示形式时,应该调用StringIO.string,而不是.read考虑到这一点,使您的第一个示例工作所需的最小更改是更改以下内容:
sio = StringIO.new(request.body.to_s)

对此:
sio = StringIO.new(request.body.string)

但是,这又是一个不必要的将a.to_s转换为字符串并返回aStringIO的过程。

关于ruby - 如何在Ruby Sinatra中读取GZIP有效负载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54192368/

10-12 21:41