2012-01-08 9 views
15

Prima di tutto c'è uno question con lo stesso titolo qui su SO ma non è quello che sto cercando e non ha una risposta completa neanche.Download di un'immagine tramite XMLHttpRequest in un userscript

Quindi ecco la mia domanda. Diciamo che ho questo URL che indirizza a un'immagine.

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

Una volta ho messo questo parametro ?dl=1 alla fine dell'URL, diventa scaricabile.

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

Sto provando a fare questo compito tramite un userscript. Quindi ho usato XMLHttpRequest per quello.

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

Questo è un fiddle.

Ma non funziona. Bare con me perché sono abbastanza nuovo in JavaScript e non ho fatto nulla nemmeno con AJAX. Ho cercato spesso su google per campioni o altro, ma senza risultato.

Per favore qualcuno può guidarmi su come farlo?

+0

'dl' argomento è completamente fasullo nel tuo caso – OnTheFly

+0

@ user539484 what do u significa? funziona. basta copiarlo e incollarlo sulla barra degli indirizzi. – Isuru

+0

Intendo, guarda le intestazioni di risposta che provoca. Non rilevante qui. – OnTheFly

risposta

20

XMLHttpRequest non funziona cross-domain, ma poiché questa è una userscript Chrome ora supporta GM_xmlhttpRequest() in soli userscripts.

Qualcosa del genere dovrebbe funzionare, notare che è asincrona:

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




Per quanto riguarda ottenere e utilizzando i dati di immagine effettivi, che è un importante dolore per allenarsi.

  • È possibile utilizzare la nuova funzionalità .responseType = "blob"; in Firefox, ma Chrome does not yet support it.

  • In Chrome o Firefox, per lo stesso dominio solo, è possibile utilizzare la nuova XHR2 in questo modo:
    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); 
    } 
    


  • Purtroppo, GM_xmlhttpRequest() non lo fa (ancora) supporto impostazione responseType.


Così, per lo script GM o applicazioni userscript, dobbiamo usare uno schema di codifica Base64 personalizzato come in "Javascript Hacks: Using XHR to load binary data".

Il codice di script diventa qualcosa di simile:

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

sì, funziona! Grazie. :) piccola domanda, come si può effettivamente scaricare l'immagine ora? Ho provato tutti gli altri metodi, ma tutti restituiscono informazioni, stato della richiesta ecc. – Isuru

+0

ok .. Ho letto sull'argomento 'overrideMimeType' su greasespot ma non offre molti dettagli. Grazie :) – Isuru

+1

Ok, ho aggiornato la risposta mostrando come afferrare e base64 codificare i dati (che consente di utilizzarli nella pagina o AJAXed in un server in una forma utilizzabile). –

3

Si sta tentando di richiedere una risorsa utilizzando XHR che si trova su un dominio diverso ed è quindi bloccato. Utilizzare CORS per la messaggistica tra domini tramite XHR.

1

Krof Drakula ha ragione, non è possibile caricare un'immagine da un dominio diverso, ma è davvero necessario farlo? Puoi creare e aggiungere un tag img e attendere che venga caricato (con qualcosa come jQuery load()).

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

no no ... Non voglio incorporare l'immagine su una pagina. Voglio scaricarlo usando un XHR. – Isuru

+1

Non capisco davvero cosa stai cercando di fare, ma se hai bisogno di usare l'immagine su una pagina, puoi aggiungerla in un 'div' nascosto, per esempio, solo per memorizzarlo nella cache, e dopo averlo caricato con è tutto ciò di cui hai bisogno. Se hai bisogno di mostrare un dialogo di salvataggio (vedi il tuo link sopra) allora puoi semplicemente usare 'window.location = 'http: //foo.com/bar? Dl = 1''. E se davvero hai bisogno di usare XHR di CORS è probabilmente la tua unica opzione. –

Problemi correlati