I want to do an HTTP POST that looks like an HMTL form posted from a browser. Specifically, post some text fields and a file field.
我想做一个HTTP POST,看起来像从浏览器中发布的HMTL表单。特别是,发布一些文本字段和文件字段。
Posting text fields is straightforward, there's an example right there in the net/http rdocs, but I can't figure out how to post a file along with it.
发布文本字段很简单,在net/http rdocs中有一个例子,但是我不知道如何发布文件。
Net::HTTP doesn't look like the best idea. curb is looking good.
HTTP看起来不是最好的方法。抑制是好看。
12 个解决方案
#1
86
I like RestClient. It encapsulates net/http with cool features like multipart form data:
我喜欢RestClient。它用一些很酷的特性来封装net/http,比如多部分表单数据:
require 'rest_client'
RestClient.post('http://localhost:3000/foo',
:name_of_file_param => File.new('/path/to/file'))
It also supports streaming.
它还支持流媒体。
gem install rest-client
will get you started.
gem安装rest-client将帮助您入门。
#2
33
I can't say enough good things about Nick Sieger's multipart-post library.
关于尼克·西格(Nick Sieger)的multipart-post库,我要说的还不够多。
It adds support for multipart posting directly to Net::HTTP, removing your need to manually worry about boundaries or big libraries that may have different goals than your own.
它增加了对多部分直接发布到Net::HTTP的支持,消除了手动担心边界或大型库的需要,这些库可能与您自己的目标不同。
Here is a little example on how to use it from the README:
下面是一个如何从自述中使用它的小例子:
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
File.open("./image.jpg") do |jpg|
req = Net::HTTP::Post::Multipart.new url.path,
"file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
end
You can check out the library here: http://github.com/nicksieger/multipart-post
您可以在这里查看库:http://github.com/nicksieger/multipart-post
or install it with:
或安装:
$ sudo gem install multipart-post
If you're connecting via SSL you need to start the connection like this:
如果您正在通过SSL连接,您需要这样启动连接:
n = Net::HTTP.new(url.host, url.port)
n.use_ssl = true
# for debugging dev server
#n.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = n.start do |http|
#3
27
curb
looks like a great solution, but in case it doesn't meet your needs, you can do it with Net::HTTP
. A multipart form post is just a carefully-formatted string with some extra headers. It seems like every Ruby programmer who needs to do multipart posts ends up writing their own little library for it, which makes me wonder why this functionality isn't built-in. Maybe it is... Anyway, for your reading pleasure, I'll go ahead and give my solution here. This code is based off of examples I found on a couple of blogs, but I regret that I can't find the links anymore. So I guess I just have to take all the credit for myself...
遏制看起来是一个很好的解决方案,但是如果它不能满足您的需求,您可以使用Net::HTTP来实现。多部分表单post只是一个格式严谨的字符串,包含一些额外的标题。似乎每个需要多部分文章的Ruby程序员最后都为它编写了自己的小库,这让我想知道为什么这个功能不是内置的。也许是……无论如何,为了你的阅读乐趣,我将继续,并给出我的解决方案。这段代码基于我在几个博客上找到的例子,但是我很遗憾我再也找不到链接了。所以我想我得把所有的功劳都归给自己……
The module I wrote for this contains one public class, for generating the form data and headers out of a hash of String
and File
objects. So for example, if you wanted to post a form with a string parameter named "title" and a file parameter named "document", you would do the following:
我为此编写的模块包含一个公共类,用于从字符串和文件对象的散列中生成表单数据和头部。因此,例如,如果您想发布一个带有名为“title”的字符串参数和名为“document”的文件参数的表单,您可以执行以下操作:
#prepare the query
data, headers = Multipart::Post.prepare_query("title" => my_string, "document" => my_file)
Then you just do a normal POST
with Net::HTTP
:
然后你只需要用Net::HTTP:
http = Net::HTTP.new(upload_uri.host, upload_uri.port)
res = http.start {|con| con.post(upload_uri.path, data, headers) }
Or however else you want to do the POST
. The point is that Multipart
returns the data and headers that you need to send. And that's it! Simple, right? Here's the code for the Multipart module (you need the mime-types
gem):
或者其他你想做的事情。重点是Multipart返回您需要发送的数据和头部。这是它!简单,是吧?这是多部分模块的代码(您需要mime类型gem):
# 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
#4
17
Here is my solution after trying other ones available on this post, I'm using it to upload photo on TwitPic:
这是我的解决方案,在尝试了其他可用的在这篇文章,我正在用它上传照片在TwitPic:
def upload(photo)
`curl -F media=@#{photo.path} -F username=#{@username} -F password=#{@password} -F message='#{photo.title}' http://twitpic.com/api/uploadAndPost`
end
#5
8
Ok, here's a simple example using curb.
这里有一个简单的例子。
require 'yaml'
require 'curb'
# prepare post data
post_data = fields_hash.map { |k, v| Curl::PostField.content(k, v.to_s) }
post_data << Curl::PostField.file('file', '/path/to/file'),
# post
c = Curl::Easy.new('http://localhost:3000/foo')
c.multipart_form_post = true
c.http_post(post_data)
# print response
y [c.response_code, c.body_str]
#6
3
Another one using only standard libraries:
另一个只使用标准库:
uri = 'https://some.end.point/some/path'
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'If you need some headers'
form_data = [['photos', photo.tempfile]] # or File.read()
request.set_form form_data, 'multipart/form-data'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| # pay attention to use_ssl if you need it
http.request(request)
end
Tried a lot of approaches but only this was worked for me.
尝试了很多方法,但只有这对我有效。
#7
2
restclient did not work for me until I overrode create_file_field in RestClient::Payload::Multipart.
restclient直到在restclient:::有效负载::Multipart中重写create_file_field后才为我工作。
It was creating a 'Content-Disposition: multipart/form-data' in each part where it should be ‘Content-Disposition: form-data’.
它在每个部分都创建了“内容配置:多部分/表单数据”,应该是“内容配置:表单数据”。
http://www.ietf.org/rfc/rfc2388.txt
http://www.ietf.org/rfc/rfc2388.txt
My fork is here if you need it: git@github.com:kcrawford/rest-client.git
如果你需要,我的叉子在这里:git@github.com:kcrawford/res -client.git
#8
1
Well the solution with NetHttp has a drawback that is when posting big files it loads the whole file into memory first.
NetHttp的解决方案有一个缺点,就是当发布大文件时,它首先将整个文件加载到内存中。
After playing a bit with it I came up with the following solution:
玩了一会儿之后,我想到了以下解决方案:
class Multipart
def initialize( file_names )
@file_names = file_names
end
def post( to_url )
boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
parts = []
streams = []
@file_names.each do |param_name, filepath|
pos = filepath.rindex('/')
filename = filepath[pos + 1, filepath.length - pos]
parts << StringPart.new ( "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + param_name.to_s + "\"; filename=\"" + filename + "\"\r\n" +
"Content-Type: video/x-msvideo\r\n\r\n")
stream = File.open(filepath, "rb")
streams << stream
parts << StreamPart.new (stream, File.size(filepath))
end
parts << StringPart.new ( "\r\n--" + boundary + "--\r\n" )
post_stream = MultipartStream.new( parts )
url = URI.parse( to_url )
req = Net::HTTP::Post.new(url.path)
req.content_length = post_stream.size
req.content_type = 'multipart/form-data; boundary=' + boundary
req.body_stream = post_stream
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
streams.each do |stream|
stream.close();
end
res
end
end
class StreamPart
def initialize( stream, size )
@stream, @size = stream, size
end
def size
@size
end
def read ( offset, how_much )
@stream.read ( how_much )
end
end
class StringPart
def initialize ( str )
@str = str
end
def size
@str.length
end
def read ( offset, how_much )
@str[offset, how_much]
end
end
class MultipartStream
def initialize( parts )
@parts = parts
@part_no = 0;
@part_offset = 0;
end
def size
total = 0
@parts.each do |part|
total += part.size
end
total
end
def read ( how_much )
if @part_no >= @parts.size
return nil;
end
how_much_current_part = @parts[@part_no].size - @part_offset
how_much_current_part = if how_much_current_part > how_much
how_much
else
how_much_current_part
end
how_much_next_part = how_much - how_much_current_part
current_part = @parts[@part_no].read(@part_offset, how_much_current_part )
if how_much_next_part > 0
@part_no += 1
@part_offset = 0
next_part = read ( how_much_next_part )
current_part + if next_part
next_part
else
''
end
else
@part_offset += how_much_current_part
current_part
end
end
end
#9
1
there's also nick sieger's multipart-post to add to the long list of possible solutions.
尼克·西格(nick sieger)的《multipart-post》(multipart- part-post)也加入了可能解决方案的列表。
#10
1
Fast forward to 2017, ruby
stdlib
net/http
has this built-in since 1.9.3
快进到2017年,ruby stdlib net/http自1.9.3以来就内置了这个功能
Net::HTTPRequest#set_form): Added to support both application/x-www-form-urlencoded and multipart/form-data.
Net: HTTPRequest#set_form):添加来支持应用程序/x-www-form- urlencodes和多部分/表单数据。
https://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTPHeader.html#method-i-set_form
https://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTPHeader.html method-i-set_form
We can even use IO
which does not support :size
to stream the form data.
我们甚至可以使用不支持的IO:size来流数据。
Hoping that this answer can really help someone :)
希望这个答案能真正帮助某人:
P.S. I only tested this in ruby 2.3.1
我只在ruby 2.3.1中测试过。
#11
0
I had the same problem (need to post to jboss web server). Curb works fine for me, except that it caused ruby to crash (ruby 1.8.7 on ubuntu 8.10) when I use session variables in the code.
我也有同样的问题(需要发布到jboss web服务器)。ruby在代码中使用会话变量会导致ruby崩溃(ubuntu 8.10上的ruby 1.8.7)。
I dig into the rest-client docs, could not find indication of multipart support. I tried the rest-client examples above but jboss said the http post is not multipart.
我深入研究了rest-client文档,没有发现多部分支持的迹象。我尝试了上面的rest-client示例,但是jboss说http post不是多部分的。
#12
0
The multipart-post gem works pretty well with Rails 4 Net::HTTP, no other special gem
multipart-post gem与Rails 4 Net::HTTP合作得很好,没有其他特殊的gem
def model_params
require_params = params.require(:model).permit(:param_one, :param_two, :param_three, :avatar)
require_params[:avatar] = model_params[:avatar].present? ? UploadIO.new(model_params[:avatar].tempfile, model_params[:avatar].content_type, model_params[:avatar].original_filename) : nil
require_params
end
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
Net::HTTP.start(url.host, url.port) do |http|
req = Net::HTTP::Post::Multipart.new(url, model_params)
key = "authorization_key"
req.add_field("Authorization", key) #add to Headers
http.use_ssl = (url.scheme == "https")
http.request(req)
end
https://github.com/Feuda/multipart-post/tree/patch-1
https://github.com/Feuda/multipart-post/tree/patch-1
#1
86
I like RestClient. It encapsulates net/http with cool features like multipart form data:
我喜欢RestClient。它用一些很酷的特性来封装net/http,比如多部分表单数据:
require 'rest_client'
RestClient.post('http://localhost:3000/foo',
:name_of_file_param => File.new('/path/to/file'))
It also supports streaming.
它还支持流媒体。
gem install rest-client
will get you started.
gem安装rest-client将帮助您入门。
#2
33
I can't say enough good things about Nick Sieger's multipart-post library.
关于尼克·西格(Nick Sieger)的multipart-post库,我要说的还不够多。
It adds support for multipart posting directly to Net::HTTP, removing your need to manually worry about boundaries or big libraries that may have different goals than your own.
它增加了对多部分直接发布到Net::HTTP的支持,消除了手动担心边界或大型库的需要,这些库可能与您自己的目标不同。
Here is a little example on how to use it from the README:
下面是一个如何从自述中使用它的小例子:
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
File.open("./image.jpg") do |jpg|
req = Net::HTTP::Post::Multipart.new url.path,
"file" => UploadIO.new(jpg, "image/jpeg", "image.jpg")
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
end
You can check out the library here: http://github.com/nicksieger/multipart-post
您可以在这里查看库:http://github.com/nicksieger/multipart-post
or install it with:
或安装:
$ sudo gem install multipart-post
If you're connecting via SSL you need to start the connection like this:
如果您正在通过SSL连接,您需要这样启动连接:
n = Net::HTTP.new(url.host, url.port)
n.use_ssl = true
# for debugging dev server
#n.verify_mode = OpenSSL::SSL::VERIFY_NONE
res = n.start do |http|
#3
27
curb
looks like a great solution, but in case it doesn't meet your needs, you can do it with Net::HTTP
. A multipart form post is just a carefully-formatted string with some extra headers. It seems like every Ruby programmer who needs to do multipart posts ends up writing their own little library for it, which makes me wonder why this functionality isn't built-in. Maybe it is... Anyway, for your reading pleasure, I'll go ahead and give my solution here. This code is based off of examples I found on a couple of blogs, but I regret that I can't find the links anymore. So I guess I just have to take all the credit for myself...
遏制看起来是一个很好的解决方案,但是如果它不能满足您的需求,您可以使用Net::HTTP来实现。多部分表单post只是一个格式严谨的字符串,包含一些额外的标题。似乎每个需要多部分文章的Ruby程序员最后都为它编写了自己的小库,这让我想知道为什么这个功能不是内置的。也许是……无论如何,为了你的阅读乐趣,我将继续,并给出我的解决方案。这段代码基于我在几个博客上找到的例子,但是我很遗憾我再也找不到链接了。所以我想我得把所有的功劳都归给自己……
The module I wrote for this contains one public class, for generating the form data and headers out of a hash of String
and File
objects. So for example, if you wanted to post a form with a string parameter named "title" and a file parameter named "document", you would do the following:
我为此编写的模块包含一个公共类,用于从字符串和文件对象的散列中生成表单数据和头部。因此,例如,如果您想发布一个带有名为“title”的字符串参数和名为“document”的文件参数的表单,您可以执行以下操作:
#prepare the query
data, headers = Multipart::Post.prepare_query("title" => my_string, "document" => my_file)
Then you just do a normal POST
with Net::HTTP
:
然后你只需要用Net::HTTP:
http = Net::HTTP.new(upload_uri.host, upload_uri.port)
res = http.start {|con| con.post(upload_uri.path, data, headers) }
Or however else you want to do the POST
. The point is that Multipart
returns the data and headers that you need to send. And that's it! Simple, right? Here's the code for the Multipart module (you need the mime-types
gem):
或者其他你想做的事情。重点是Multipart返回您需要发送的数据和头部。这是它!简单,是吧?这是多部分模块的代码(您需要mime类型gem):
# 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
#4
17
Here is my solution after trying other ones available on this post, I'm using it to upload photo on TwitPic:
这是我的解决方案,在尝试了其他可用的在这篇文章,我正在用它上传照片在TwitPic:
def upload(photo)
`curl -F media=@#{photo.path} -F username=#{@username} -F password=#{@password} -F message='#{photo.title}' http://twitpic.com/api/uploadAndPost`
end
#5
8
Ok, here's a simple example using curb.
这里有一个简单的例子。
require 'yaml'
require 'curb'
# prepare post data
post_data = fields_hash.map { |k, v| Curl::PostField.content(k, v.to_s) }
post_data << Curl::PostField.file('file', '/path/to/file'),
# post
c = Curl::Easy.new('http://localhost:3000/foo')
c.multipart_form_post = true
c.http_post(post_data)
# print response
y [c.response_code, c.body_str]
#6
3
Another one using only standard libraries:
另一个只使用标准库:
uri = 'https://some.end.point/some/path'
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'If you need some headers'
form_data = [['photos', photo.tempfile]] # or File.read()
request.set_form form_data, 'multipart/form-data'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| # pay attention to use_ssl if you need it
http.request(request)
end
Tried a lot of approaches but only this was worked for me.
尝试了很多方法,但只有这对我有效。
#7
2
restclient did not work for me until I overrode create_file_field in RestClient::Payload::Multipart.
restclient直到在restclient:::有效负载::Multipart中重写create_file_field后才为我工作。
It was creating a 'Content-Disposition: multipart/form-data' in each part where it should be ‘Content-Disposition: form-data’.
它在每个部分都创建了“内容配置:多部分/表单数据”,应该是“内容配置:表单数据”。
http://www.ietf.org/rfc/rfc2388.txt
http://www.ietf.org/rfc/rfc2388.txt
My fork is here if you need it: git@github.com:kcrawford/rest-client.git
如果你需要,我的叉子在这里:git@github.com:kcrawford/res -client.git
#8
1
Well the solution with NetHttp has a drawback that is when posting big files it loads the whole file into memory first.
NetHttp的解决方案有一个缺点,就是当发布大文件时,它首先将整个文件加载到内存中。
After playing a bit with it I came up with the following solution:
玩了一会儿之后,我想到了以下解决方案:
class Multipart
def initialize( file_names )
@file_names = file_names
end
def post( to_url )
boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
parts = []
streams = []
@file_names.each do |param_name, filepath|
pos = filepath.rindex('/')
filename = filepath[pos + 1, filepath.length - pos]
parts << StringPart.new ( "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"" + param_name.to_s + "\"; filename=\"" + filename + "\"\r\n" +
"Content-Type: video/x-msvideo\r\n\r\n")
stream = File.open(filepath, "rb")
streams << stream
parts << StreamPart.new (stream, File.size(filepath))
end
parts << StringPart.new ( "\r\n--" + boundary + "--\r\n" )
post_stream = MultipartStream.new( parts )
url = URI.parse( to_url )
req = Net::HTTP::Post.new(url.path)
req.content_length = post_stream.size
req.content_type = 'multipart/form-data; boundary=' + boundary
req.body_stream = post_stream
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
streams.each do |stream|
stream.close();
end
res
end
end
class StreamPart
def initialize( stream, size )
@stream, @size = stream, size
end
def size
@size
end
def read ( offset, how_much )
@stream.read ( how_much )
end
end
class StringPart
def initialize ( str )
@str = str
end
def size
@str.length
end
def read ( offset, how_much )
@str[offset, how_much]
end
end
class MultipartStream
def initialize( parts )
@parts = parts
@part_no = 0;
@part_offset = 0;
end
def size
total = 0
@parts.each do |part|
total += part.size
end
total
end
def read ( how_much )
if @part_no >= @parts.size
return nil;
end
how_much_current_part = @parts[@part_no].size - @part_offset
how_much_current_part = if how_much_current_part > how_much
how_much
else
how_much_current_part
end
how_much_next_part = how_much - how_much_current_part
current_part = @parts[@part_no].read(@part_offset, how_much_current_part )
if how_much_next_part > 0
@part_no += 1
@part_offset = 0
next_part = read ( how_much_next_part )
current_part + if next_part
next_part
else
''
end
else
@part_offset += how_much_current_part
current_part
end
end
end
#9
1
there's also nick sieger's multipart-post to add to the long list of possible solutions.
尼克·西格(nick sieger)的《multipart-post》(multipart- part-post)也加入了可能解决方案的列表。
#10
1
Fast forward to 2017, ruby
stdlib
net/http
has this built-in since 1.9.3
快进到2017年,ruby stdlib net/http自1.9.3以来就内置了这个功能
Net::HTTPRequest#set_form): Added to support both application/x-www-form-urlencoded and multipart/form-data.
Net: HTTPRequest#set_form):添加来支持应用程序/x-www-form- urlencodes和多部分/表单数据。
https://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTPHeader.html#method-i-set_form
https://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTPHeader.html method-i-set_form
We can even use IO
which does not support :size
to stream the form data.
我们甚至可以使用不支持的IO:size来流数据。
Hoping that this answer can really help someone :)
希望这个答案能真正帮助某人:
P.S. I only tested this in ruby 2.3.1
我只在ruby 2.3.1中测试过。
#11
0
I had the same problem (need to post to jboss web server). Curb works fine for me, except that it caused ruby to crash (ruby 1.8.7 on ubuntu 8.10) when I use session variables in the code.
我也有同样的问题(需要发布到jboss web服务器)。ruby在代码中使用会话变量会导致ruby崩溃(ubuntu 8.10上的ruby 1.8.7)。
I dig into the rest-client docs, could not find indication of multipart support. I tried the rest-client examples above but jboss said the http post is not multipart.
我深入研究了rest-client文档,没有发现多部分支持的迹象。我尝试了上面的rest-client示例,但是jboss说http post不是多部分的。
#12
0
The multipart-post gem works pretty well with Rails 4 Net::HTTP, no other special gem
multipart-post gem与Rails 4 Net::HTTP合作得很好,没有其他特殊的gem
def model_params
require_params = params.require(:model).permit(:param_one, :param_two, :param_three, :avatar)
require_params[:avatar] = model_params[:avatar].present? ? UploadIO.new(model_params[:avatar].tempfile, model_params[:avatar].content_type, model_params[:avatar].original_filename) : nil
require_params
end
require 'net/http/post/multipart'
url = URI.parse('http://www.example.com/upload')
Net::HTTP.start(url.host, url.port) do |http|
req = Net::HTTP::Post::Multipart.new(url, model_params)
key = "authorization_key"
req.add_field("Authorization", key) #add to Headers
http.use_ssl = (url.scheme == "https")
http.request(req)
end
https://github.com/Feuda/multipart-post/tree/patch-1
https://github.com/Feuda/multipart-post/tree/patch-1