curb
sieht nach einer großartigen Lösung aus, aber falls sie nicht Ihren Anforderungen entspricht, können Sie dies tun Net::HTTP
. Ein mehrteiliger Formularbeitrag ist nur eine sorgfältig formatierte Zeichenfolge mit einigen zusätzlichen Überschriften. Es scheint, als würde jeder Ruby-Programmierer, der mehrteilige Posts erstellen muss, seine eigene kleine Bibliothek dafür schreiben, weshalb ich mich frage, warum diese Funktionalität nicht integriert ist. Vielleicht ist es ... Wie auch immer, für Ihr Lesevergnügen werde ich hier meine Lösung geben. Dieser Code basiert auf Beispielen, die ich in einigen Blogs gefunden habe, aber ich bedauere, dass ich die Links nicht mehr finden kann. Also muss ich wohl alle Ehre für mich selbst aufbringen ...
Das Modul, das ich dafür geschrieben habe, enthält eine öffentliche Klasse zum Generieren der Formulardaten und Header aus einem Hash von String
und File
Objekten. Wenn Sie beispielsweise ein Formular mit einem Zeichenfolgenparameter namens "title" und einem Dateiparameter mit dem Namen "document" veröffentlichen möchten, gehen Sie wie folgt vor:
#prepare the query
data, headers = Multipart::Post.prepare_query("title" => my_string, "document" => my_file)
Dann machst du einfach ein normales POST
mit Net::HTTP
:
http = Net::HTTP.new(upload_uri.host, upload_uri.port)
res = http.start {|con| con.post(upload_uri.path, data, headers) }
Oder wie auch immer Sie das tun möchten POST
. Der Punkt ist, dass Multipart
die Daten und Header zurückgegeben werden, die Sie senden müssen. Und das ist es! Einfach, richtig? Hier ist der Code für das Multipart-Modul (Sie benötigen das mime-types
Juwel):
# Takes a hash of string and file parameters and returns a string of text
# formatted to be sent as a multipart form post.
#
# Author:: Cody Brimhall <mailto:brimhall@somuchwit.com>
# Created:: 22 Feb 2008
# License:: Distributed under the terms of the WTFPL (http://www.wtfpl.net/txt/copying/)
require 'rubygems'
require 'mime/types'
require 'cgi'
module Multipart
VERSION = "1.0.0"
# Formats a given hash as a multipart form post
# If a hash value responds to :string or :read messages, then it is
# interpreted as a file and processed accordingly; otherwise, it is assumed
# to be a string
class Post
# We have to pretend we're a web browser...
USERAGENT = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
BOUNDARY = "0123456789ABLEWASIEREISAWELBA9876543210"
CONTENT_TYPE = "multipart/form-data; boundary=#{ BOUNDARY }"
HEADER = { "Content-Type" => CONTENT_TYPE, "User-Agent" => USERAGENT }
def self.prepare_query(params)
fp = []
params.each do |k, v|
# Are we trying to make a file parameter?
if v.respond_to?(:path) and v.respond_to?(:read) then
fp.push(FileParam.new(k, v.path, v.read))
# We must be trying to make a regular parameter
else
fp.push(StringParam.new(k, v))
end
end
# Assemble the request body using the special multipart format
query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
return query, HEADER
end
end
private
# Formats a basic string key/value pair for inclusion with a multipart post
class StringParam
attr_accessor :k, :v
def initialize(k, v)
@k = k
@v = v
end
def to_multipart
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
end
end
# Formats the contents of a file or string for inclusion with a multipart
# form post
class FileParam
attr_accessor :k, :filename, :content
def initialize(k, filename, content)
@k = k
@filename = filename
@content = content
end
def to_multipart
# If we can tell the possible mime-type from the filename, use the
# first in the list; otherwise, use "application/octet-stream"
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; filename=\"#{ filename }\"\r\n" +
"Content-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n"
end
end
end