我正在创建一个API服务,允许人们向API调用提供图像的URL,然后服务下载图像进行处理。
如何确保有人不会给我一个像5MB图片的网址?有没有办法限制请求?
这是我到目前为止所掌握的,基本上可以抓住一切。
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) { |http|
http.request(req)
}
谢谢, 康拉德
答案 0 :(得分:6)
要正确执行此操作,您需要使用一个HTTP库,该库允许您在收到字节时对其进行计数,如果超过阈值则中止。我可能会推荐Curb而不是Net :: HTTP。 (甚至可以使用Net :: HTTP执行此操作吗?)如果使用on_body和/或on_progress回调,则可以计算传入的字节数并在收到过大的文件时中止响应。显然,正如cwninja已经指出的那样,如果你收到的Content-Length标题大于你的阈值,你也想要中止。遏制也是notably faster than Net::HTTP。
答案 1 :(得分:2)
首先尝试运行:
Net::HTTP.start(url.host, url.port) { |http|
response = http.request_head(url.path)
raise "File too big." if response['content-length'].to_i > 5*1024*1024
}
您仍然遇到竞争条件(有人可能在您执行HEAD
请求后换出文件),但在简单的情况下,这会向服务器询问它将从{{1}发回的标头请求。
答案 2 :(得分:1)
另一种限制下载大小的方法(完整代码应检查响应状态,异常处理等。这只是一个例子)
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new uri.request_uri
http.request request do |response|
# check response codes here
body=''
response.read_body do |chunk|
body += chunk
break if body.size > MY_SAFE_SIZE_LIMIT
end
break
end
end
答案 3 :(得分:1)
结合其他两个答案,我想1)检查大小标题,2)观察块的大小,同时3)supporting https和4)积极执行超时。这是我提出的帮手:
require "net/http"
require 'uri'
module FetchUtil
# Fetch a URL, with a given max bytes, and a given timeout
def self.fetch_url url, timeout_sec=5, max_bytes=5*1024*1024
uri = URI.parse(url)
t0 = Time.now.to_f
body = ''
Net::HTTP.start(uri.host, uri.port, :use_ssl => (uri.scheme == 'https')) { |http|
http.open_timeout = timeout_sec
http.read_timeout = timeout_sec
# First make a HEAD request and check the content-length
check_res = http.request_head(uri.path)
raise "File too big" if check_res['content-length'].to_i > max_bytes
# Then fetch in chunks and bail on either timeout or max_bytes
# (Note: timeout won't work unless bytes are streaming in...)
http.request_get(uri.path) do |res|
res.read_body do |chunk|
raise "Timeout error" if (Time.now().to_f-t0 > timeout_sec)
raise "Filesize exceeded" if (body.length+chunk.length > max_bytes)
body += chunk
end
end
}
return body
end
end