2012-01-08 6 views
15

Trước hết có một số question có cùng tiêu đề ở đây trên SO nhưng không phải là thứ tôi đang tìm kiếm và cũng không có câu trả lời hoàn chỉnh.Tải xuống hình ảnh bằng cách sử dụng XMLHttpRequest trong một số người dùng

Vì vậy, đây là câu hỏi của tôi. Giả sử tôi có URL này hướng đến một hình ảnh.

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

Khi tôi đặt thông số này ?dl=1 vào cuối URL, nó sẽ có thể tải xuống.

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

Tôi đang cố gắng thực hiện tác vụ này thông qua usercript. Vì vậy, tôi đã sử dụng XMLHttpRequest cho điều đó.

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); 
} 

Đây là fiddle.

Nhưng nó không hoạt động. Bare với tôi cho tôi là khá mới với JavaScript và tôi đã không làm bất cứ điều gì với AJAX hoặc. Tôi googled rất nhiều cho mẫu hoặc bất cứ điều gì nhưng vô ích.

Bạn có thể hướng dẫn tôi cách thực hiện việc này không?

+0

'dl' đối số là hoàn toàn không có thật trong trường hợp của bạn – OnTheFly

+0

@ user539484 gì u nghĩa là gì? nó hoạt động. chỉ cần sao chép và dán nó vào thanh địa chỉ. – Isuru

+0

Ý tôi là, hãy nhìn vào các tiêu đề phản hồi mà nó gây ra. Không có liên quan ở đây. – OnTheFly

Trả lời

20

XMLHttpRequest sẽ không hoạt động cross-domain, nhưng vì đây là một UserScript Chrome bây giờ hỗ trợ GM_xmlhttpRequest() chỉ userscripts.

Something như thế này nên làm việc, lưu ý rằng nó là không đồng bộ:

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); 
        } 
}); 




Đối với nhận và sử dụng các dữ liệu hình ảnh thực tế, đó là một lớn đau để làm việc.

  • Bạn có thể sử dụng .responseType = "blob"; chức năng mới trong Firefox nhưng Chrome does not yet support it.

  • Trong Chrome hoặc Firefox, cho cùng một miền chỉ, bạn có thể sử dụng mới XHR2 như vậy:
    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); 
    } 
    


  • Thật không may, GM_xmlhttpRequest() không (chưa) hỗ trợ cài đặt responseType.


Vì vậy, đối với kịch bản GM hoặc các ứng dụng UserScript, chúng ta phải sử dụng một chương trình mã hóa tùy chỉnh base64 như trong "Javascript Hacks: Using XHR to load binary data".

Mã kịch bản trở thành một cái gì đó như:

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" 
          + "/=", 
     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; 
} 
+0

có, nó hoạt động! Cảm ơn bạn. :) câu hỏi nhỏ, làm thế nào bạn có thể thực sự tải xuống hình ảnh ngay bây giờ? Tôi đã thử tất cả các phương pháp khác nhưng tất cả đều trả về thông tin, trạng thái yêu cầu, vv .. – Isuru

+0

okay .. Tôi đã đọc về đối số 'overrideMimeType' trên greasespot nhưng nó cũng không cung cấp nhiều chi tiết. Cảm ơn bạn :) – Isuru

+1

Được rồi, cập nhật câu trả lời cho thấy cách lấy và mã hóa base64 dữ liệu (cho phép nó được sử dụng trong trang hoặc AJAXed tới máy chủ ở dạng có thể sử dụng). –

3

Bạn đang cố gắng yêu cầu tài nguyên bằng cách sử dụng XHR trên miền khác và do đó bị chặn. Sử dụng CORS cho nhắn tin đa miền sử dụng XHR.

1

Krof Drakula là đúng, bạn không thể tải hình ảnh từ một miền khác, nhưng bạn có thực sự cần phải làm điều này không? Bạn có thể tạo và gắn thêm một thẻ img và đợi cho nó tải (với một cái gì đó như jQuery load()).

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

không không ... Tôi không muốn nhúng hình ảnh trên một trang. Tôi muốn tải xuống bằng XHR. – Isuru

+1

Tôi không thực sự hiểu những gì bạn đang cố gắng làm, nhưng nếu bạn cần phải sử dụng hình ảnh trên một trang, bạn có thể thêm nó vào một 'div' ẩn, ví dụ, chỉ để cache nó, và sau khi tải làm với nó bất cứ điều gì bạn cần. Nếu bạn cần hiển thị hộp thoại lưu (xem liên kết của bạn ở trên) thì bạn chỉ có thể sử dụng 'window.location = 'http: //foo.com/bar? Dl = 1''. Và nếu bạn thực sự cần phải sử dụng XHR hơn CORS có lẽ là lựa chọn duy nhất của bạn. –