【问题标题】:How to load foreign image via POST request in browser?如何在浏览器中通过 POST 请求加载外国图像?
【发布时间】: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:我真的不知道你在说什么,或者想说什么。

标签: javascript ajax html image post


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    相关资源
    最近更新 更多