Javascript 在用户脚本中使用 XMLHttpRequest 下载图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8778863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 07:28:53  来源:igfitidea点击:

Downloading an image using XMLHttpRequest in a userscript

javascriptxmlhttprequestdownloaduserscripts

提问by Isuru

First of all there is a questionwith the same title here on SO but its not what I'm looking for and it doesn't have a complete answer either.

首先,SO 上有一个具有相同标题的问题,但这不是我要找的,也没有完整的答案。

So here's my question. Say I have this URL which directs to an image.

所以这是我的问题。假设我有这个指向图像的 URL。

https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg

Once I put this parameter ?dl=1to the end of the URL, it becomes downloadable.

一旦我把这个参数放在?dl=1URL 的末尾,它就可以下载了。

https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1

I'm trying to do this task through a userscript. So I used XMLHttpRequest for that.

我正在尝试通过用户脚本完成此任务。所以我为此使用了 XMLHttpRequest。

var url = "https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1";

var request = new XMLHttpRequest();  
request.open("GET", url, false);   
request.send(null);  

if (request.status === 200) 
{  
    alert(request.statusText);
}

Here is a fiddle.

这是一个小提琴

But it does not work.

但它不起作用。

回答by Brock Adams

XMLHttpRequestwill not work cross-domain, but since this is a userscriptChrome now supports GM_xmlhttpRequest()in userscripts only.

XMLHttpRequest不会跨域工作,但由于这是一个用户脚本,Chrome 现在GM_xmlhttpRequest()仅在用户脚本中支持。

Something like this should work, note that it is asynchronous:

这样的事情应该可以工作,请注意它是异步的:

GM_xmlhttpRequest ( {
    method:         'GET',
    url:            'https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1',
    onload:         function (responseDetails) {
                        alert(responseDetails.statusText);
                    }
} );







As for getting and using the actual image data, that is a major pain to work out.

至于获取和使用实际的图像数据,这是一个很大的难题。

  • You can use the new .responseType = "blob";functionality in Firefox but Chrome does not yet support it.

  • In Chrome or Firefox, for the same domain only, you can use the new XHR2like so:
    See it in action at jsBin.

    BlobBuilder             = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
    
    var url                 = "http://jsbin.com/images/gear.png";
    var request             = new XMLHttpRequest();
    request.open ("GET", url, false);
    request.responseType    = "arraybuffer";
    request.send (null);
    
    if (request.status === 200) {
        var bb              = new BlobBuilder ();
        bb.append (request.response); // Note: not request.responseText
    
        var blob            = bb.getBlob ('image/png');
        var reader          = new FileReader ();
        reader.onload       = function (zFR_Event) {
            $("body").prepend ('<p>New image: <img src="' + zFR_Event.target.result + '"></p>')
        };
    
        reader.readAsDataURL (blob);
    }
    


  • Unfortunately, GM_xmlhttpRequest()does not (yet) support setting responseType.
  • 您可以.responseType = "blob";在 Firefox 中使用新功能,但Chrome 尚不支持它

  • 在 Chrome 或 Firefox 中,仅对于同一个域,您可以像这样使用新的XHR2
    在 jsBin 上查看它的实际效果。

    BlobBuilder             = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
    
    var url                 = "http://jsbin.com/images/gear.png";
    var request             = new XMLHttpRequest();
    request.open ("GET", url, false);
    request.responseType    = "arraybuffer";
    request.send (null);
    
    if (request.status === 200) {
        var bb              = new BlobBuilder ();
        bb.append (request.response); // Note: not request.responseText
    
        var blob            = bb.getBlob ('image/png');
        var reader          = new FileReader ();
        reader.onload       = function (zFR_Event) {
            $("body").prepend ('<p>New image: <img src="' + zFR_Event.target.result + '"></p>')
        };
    
        reader.readAsDataURL (blob);
    }
    


  • 不幸的是,GM_xmlhttpRequest()不(还)支持设置responseType.



So, for GM script or userscript applications, we have to use a custom base64 encoding scheme like in "Javascript Hacks: Using XHR to load binary data".


因此,对于 GM 脚本或用户脚本应用程序,我们必须使用自定义的 base64 编码方案,如“Javascript Hacks: Using XHR to load binary data”

The script code becomes something like:

脚本代码变成了这样:

var imgUrl              = "http://jsbin.com/images/gear.png";

GM_xmlhttpRequest ( {
    method:         'GET',
    url:            imgUrl,
    onload:         function (respDetails) {
                        var binResp     = customBase64Encode (respDetails.responseText);

                        /*-- Here, we just demo that we have a valid base64 encoding
                            by inserting the image into the page.
                            We could just as easily AJAX-off the data instead.
                        */
                        var zImgPara    = document.createElement ('p');
                        var zTargetNode = document.querySelector ("body *"); //1st child

                        zImgPara.innerHTML = 'Image: <img src="data:image/png;base64,'
                                           + binResp + '">';
                        zTargetNode.parentNode.insertBefore (zImgPara, zTargetNode);
                    },
    overrideMimeType: 'text/plain; charset=x-user-defined'
} );


function customBase64Encode (inputStr) {
    var
        bbLen               = 3,
        enCharLen           = 4,
        inpLen              = inputStr.length,
        inx                 = 0,
        jnx,
        keyStr              = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
                            + "0123456789+/=",
        output              = "",
        paddingBytes        = 0;
    var
        bytebuffer          = new Array (bbLen),
        encodedCharIndexes  = new Array (enCharLen);

    while (inx < inpLen) {
        for (jnx = 0;  jnx < bbLen;  ++jnx) {
            /*--- Throw away high-order byte, as documented at:
              https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
            */
            if (inx < inpLen)
                bytebuffer[jnx] = inputStr.charCodeAt (inx++) & 0xff;
            else
                bytebuffer[jnx] = 0;
        }

        /*--- Get each encoded character, 6 bits at a time.
            index 0: first  6 bits
            index 1: second 6 bits
                        (2 least significant bits from inputStr byte 1
                         + 4 most significant bits from byte 2)
            index 2: third  6 bits
                        (4 least significant bits from inputStr byte 2
                         + 2 most significant bits from byte 3)
            index 3: forth  6 bits (6 least significant bits from inputStr byte 3)
        */
        encodedCharIndexes[0] = bytebuffer[0] >> 2;
        encodedCharIndexes[1] = ( (bytebuffer[0] & 0x3) << 4)   |  (bytebuffer[1] >> 4);
        encodedCharIndexes[2] = ( (bytebuffer[1] & 0x0f) << 2)  |  (bytebuffer[2] >> 6);
        encodedCharIndexes[3] = bytebuffer[2] & 0x3f;

        //--- Determine whether padding happened, and adjust accordingly.
        paddingBytes          = inx - (inpLen - 1);
        switch (paddingBytes) {
            case 1:
                // Set last character to padding char
                encodedCharIndexes[3] = 64;
                break;
            case 2:
                // Set last 2 characters to padding char
                encodedCharIndexes[3] = 64;
                encodedCharIndexes[2] = 64;
                break;
            default:
                break; // No padding - proceed
        }

        /*--- Now grab each appropriate character out of our keystring,
            based on our index array and append it to the output string.
        */
        for (jnx = 0;  jnx < enCharLen;  ++jnx)
            output += keyStr.charAt ( encodedCharIndexes[jnx] );
    }
    return output;
}

回答by Klemen Slavi?

You are trying to request a resource using XHR that is on a different domain and is thus blocked. Use CORS for cross-domain messaging using XHR.

您正在尝试使用位于不同域上的 XHR 请求资源,因此被阻止。使用 CORS 使用 XHR 进行跨域消息传递。

回答by Daniel J F

Krof Drakula is right, you cannot load an image from a different domain, but do you really need to do this? You can create and append an imgtag and wait for it to load (with something like jQuery load()).

Krof Drakula 是对的,你不能从不同的域加载图像,但你真的需要这样做吗?您可以创建并附加一个img标签并等待它加载(使用类似 jQuery 的东西load())。

var img = document.createElement( 'img' );
img.setAttribute( 'src', url );
document.getElementsByTagName('body')[0].appendChild( img );

回答by ariel

Modern browsers have the Blobobject:

现代浏览器有Blob对象:

GM_xmlhttpRequest({
  method: "GET",
  url: url,
  headers: { referer: url, origin: url },
  responseType: 'blob',
  onload: function(resp) {
    var img = document.createElement('img');
    img.src = window.URL.createObjectURL(resp.response);
    document.body.appendChild(img);
  }
});

The headersparam will set the referrer so you can load referrer locked images.

headers参数将设置引用者,以便您可以加载引用者锁定的图像。