如何在浏览器中通过 POST 请求加载外国图像?
Posted
技术标签:
【中文标题】如何在浏览器中通过 POST 请求加载外国图像?【英文标题】:How to load foreign image via POST request in browser? 【发布时间】:2015-07-25 19:49:03 【问题描述】:我的 Web 应用程序 (html5 + javascript) 需要显示由国外 Web 服务生成的 PNG 图像。
但是,该网络服务仅支持 POST 请求。 (更准确地说,它确实提供了 GET 请求,但我必须传输大参数,因此 GET URL 变得太长。)
此外,Web 服务与 Web 应用程序具有不同的域,并且不提供正确的 CORS 标头,因此 Ajax (XMLHTTPRequest) 不起作用。
我的 Web 应用程序是否仍然可以通过 POST 请求加载和显示外部图像?
我要求的解决方案不同于我已经熟知的以下讨厌的解决方法:
没有设置转换请求的本地代理(并且还规避同源策略) 不使用某个陌生人的远程代理 不使用 Flash 不使用 Java 小程序 不使用特定于操作系统的功能,例如 ActiveX 控件但是,无法使用 Internet Explorer 的解决方案是可以接受的。即便是 Firefox 或 Chrome 特定的解决方案也值得赞赏。
【问题讨论】:
请记住,同源策略是关于不窃取 cookie 或个人数据,而不是不访问资源。如果它是关于不访问资源代理也不会工作。 服务是否返回文件或图片的网址? @DaveAlperovich:不确定“返回文件”是什么意思,但服务直接返回图像数据。它不会返回指向另一个返回图像的资源的 URL。 我想我会选择一个丑陋的 JSONP 来克服所有其他黑客。或者至少我会先尝试一下。艰难的场景。 @DaveAlperovich:我真的不知道你在说什么,或者想说什么。 【参考方案1】:可怕的黑客攻击:
向 iframe 提交表单并在 iframe 中显示图像。
(但不要这样做,这听起来像网络服务器旨在避免将图像直接嵌入其他站点。)
【讨论】:
不,Web 服务没有内联问题。只是 GET 请求太大了。我相应地调整了问题。 不设置代理我认为这是唯一可行的解决方案 这太棒了!如果图像大小可变,则图像大小可能会成为问题。 非常抱歉。我打算奖励这个答案的赏金,但由于一些不可逆转的错误,它被奖励给了另一个答案。另见:meta.stackexchange.com/questions/257105/…【参考方案2】:我有一些可能的解决方案...
解决方案 1
如果您的图像小于 25kb,您可以通过 YQL 执行以下操作:select * from data.uri where url="http://jquery.com/jquery-wp-content/themes/jquery/images/logo-jquery@2x.png"
这样您就可以抓取 base64 图像并继续。要通过 YQL 进行 POST,您应该添加类似 and postdata="foo=foo&bar=bar"
的内容,请查看 this article。
警告:这种方法的性能可能不是很好。从最终用户到 YQL 到服务的跃迁,然后一直返回,存在相当多的延迟。还有一些服务器端处理 YQL 对图像进行 base64 编码并提供一些 JSON 响应。
解决方案 2
启用 CORS 或通过其他代理。一旦你这样做了,如果你仍然无法获得 base64 数据,那么你需要做两件事。首先添加一个处理二进制的 jQuery 传输。其次处理二进制 blob 并将其转换为 base64。
这是我找到的jQuery Binary Transport
$.ajaxTransport("+binary", function(options, originalOptions, jqXHR)
// check for conditions and support for blob / arraybuffer response type
if (window.FormData && ((options.dataType && (options.dataType == 'binary')) || (options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) || (window.Blob && options.data instanceof Blob)))))
return
// create new XMLHttpRequest
send: function(headers, callback)
// setup all variables
var xhr = new XMLHttpRequest(),
url = options.url,
type = options.type,
async = options.async || true,
// blob or arraybuffer. Default is blob
dataType = options.responseType || "blob",
data = options.data || null,
username = options.username || null,
password = options.password || null;
xhr.addEventListener('load', function()
var data = ;
data[options.dataType] = xhr.response;
// make callback and send data
callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
);
xhr.open(type, url, async, username, password);
// setup custom headers
for (var i in headers )
xhr.setRequestHeader(i, headers[i] );
xhr.responseType = dataType;
xhr.send(data);
,
abort: function()
jqXHR.abort();
;
);
添加传输后,您可以发出任何类型的 AJAX 请求。
$.ajax(
type: "POST",
url: 'http://myservice.com/service/v1/somethingsomething',
dataType: 'binary',
success: function(imgData)
var img = new Image(),
reader = new window.FileReader();
reader.readAsDataURL(imgData);
reader.onloadend = function()
img.src = reader.result
$('#logo-events').append(img);
);
读者应使用Blob
并输出base64 版本。当阅读器完成转换/阅读时,它将创建和图像并将其附加到某处。 GET 或 POST 应该不再重要了。
【讨论】:
解决方案 1 建议使用一些 Yahoo 服务器作为代理。我相信这是比设置本地代理更可怕的行为。我调整了我的问题以使这一点更清楚。 -1 表示“解决方案 2”,因为它完全没有抓住重点。我对 CORS 标头没有影响,这在问题中已明确说明。而“通过其他代理”意味着设置代理,这是我所知道的确切解决方案,我正在寻求更好的解决方案。 (另外,在那种情况下,我会简单地使用 IMG 标记并且不会使用 AJAX,所以这个解决方案也被过度设计了。) @vog 仅仅因为答案是否定的并不意味着它应该得到-1。进行 POST 的唯一方法是通过 AJAX 调用。这也是 yql 的目的,它的目的是充当代理。你在问如何绕过同源策略 #1 说 #2 说不要但是如果你仍然需要 POST 这就是方法。 问题的全部意义(以及赏金)是因为它很难。答案“否”是不正确的,请参阅 Quentin 的 iframe 技巧。我正在寻找更多这样的创意。我对试图向我推销我已经知道的答案不感兴趣。【参考方案3】:我发现了这个相关的问题:Post data to JsonP
我认为它可能适用于你的情况。
基本上,将您的 jsonp 请求发送到您的服务器(同源策略应该不是问题),并将响应加载为 <img>
就像@Quentin 的回答一样,这个 hack 使用(隐藏的)Iframe
【讨论】:
以上是关于如何在浏览器中通过 POST 请求加载外国图像?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ruby 中通过 SSL 调用 HTTP POST 方法?