จะรับไฟล์หรือหยดจาก URL วัตถุได้อย่างไร


127

ฉันอนุญาตให้ผู้ใช้โหลดภาพลงในเพจผ่านการลากและวางและวิธีอื่น ๆ เมื่อภาพหลุดฉันกำลังใช้URL.createObjectURLเพื่อแปลงเป็น URL วัตถุเพื่อแสดงภาพ ฉันไม่ได้เพิกถอน url เนื่องจากใช้ซ้ำ

ดังนั้นเมื่อถึงเวลาต้องสร้างFormDataออบเจ็กต์เพื่อที่ฉันจะได้อนุญาตให้พวกเขาอัปโหลดแบบฟอร์มที่มีรูปใดรูปหนึ่งอยู่ในนั้นมีวิธีใดบ้างที่ฉันสามารถย้อนกลับ Object URL นั้นกลับไปเป็นBlobหรือFileดังนั้นฉันจึงสามารถต่อท้ายด้วยFormDataวัตถุ?


ไม่เป็นไรเกี่ยวกับสองความคิดเห็นก่อนหน้านี้สิ่งที่คุณต้องทำคือส่งXMLHttpRequestไปที่ URL หยด
gengkev

2
ทำไมไม่เก็บออบเจ็กต์ไฟล์ต้นฉบับไว้ที่ไหนสักแห่งจากนั้นใช้ URL ออบเจ็กต์เพื่อแสดงและในการส่งแบบฟอร์มให้ใช้ไฟล์ต้นฉบับ
user764754

@ user764754 เนื่องจากพยายามรับ URL ของไฟล์ที่อัปโหลดโดยผู้ใช้แสดงเป็น "C: \ fakepath"
Malcolm Salvador

คำตอบ:


89

โซลูชันที่ทันสมัย:

let blob = await fetch(url).then(r => r.blob());

url อาจเป็น url วัตถุหรือ url ธรรมดาก็ได้


3
ดี ดีใจที่ได้เห็น ES5 ทำให้สิ่งต่างๆง่ายขึ้นเช่นนี้
BrianFreud

11
และหากคุณต้องการรับไฟล์จากสัญญาโดยตรงคุณสามารถสร้างไฟล์ได้ดังนี้ let file = await fetch(url).then(r => r.blob()).then(blobFile => new File([blobFile], "fileNameGoesHere", { type: "image/png" })
dbakiu

3
ขออภัยวิธีนี้ใช้ไม่ได้กับฉันใน Chrome เบราว์เซอร์ไม่สามารถโหลด URL นี้
waldgeist

Waldgeist คุณรวมไว้ใน createObjectUrl () หรือไม่?
Matt Fletcher

73

ดังที่ gengkev กล่าวถึงในความคิดเห็นของเขาด้านบนดูเหมือนว่าวิธีที่ดีที่สุด / วิธีเดียวที่จะทำได้คือการเรียก async xhr2:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//your.blob.url.here', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status == 200) {
    var myBlob = this.response;
    // myBlob is now the blob that the object URL pointed to.
  }
};
xhr.send();

อัปเดต (2018): สำหรับสถานการณ์ที่สามารถใช้ ES5 ได้อย่างปลอดภัย Joe มีคำตอบตาม ES5 ที่ง่ายกว่าด้านล่าง


19
เมื่อใดที่คุณจะมีobjectURLที่ไม่ได้อยู่ในโดเมนและขอบเขตปัจจุบัน
BrianFreud

4
ฉันทำเช่นเดียวกับด้านบน แต่ไม่พบ 404 กับ xhr เกิดอะไรขึ้น?
albert yu

โปรดทราบว่าเบราว์เซอร์บางตัว (อ่าน IE เก่า ... ) หากคุณต้องการจัดการเหล่านั้นโปรดดูโพสต์stackoverflow.com/questions/17657184/…
mraxus

4
@BrianFreud "เมื่อใดที่คุณจะมี objectURL ที่ไม่ได้อยู่ในโดเมนและขอบเขตปัจจุบัน" ในกรณีของฉันฉันกำลังพยายามตั้งชื่อไฟล์ให้กับ Amazon S3 blob ซึ่งปัจจุบันเป็น "guid" บน S3 ที่ไม่มีนามสกุล ดังนั้นในกรณีของฉันฉันใช้การโทรข้ามโดเมน
Wagner Bertolini Junior

6
"Object URLs คือ URL ที่ชี้ไปยังไฟล์บนดิสก์" ObjectURL ตามคำจำกัดความสามารถเป็นแบบโลคัลเท่านั้น
BrianFreud

14

อาจมีคนพบว่าสิ่งนี้มีประโยชน์เมื่อทำงานกับ React / Node / Axios ฉันใช้สิ่งนี้สำหรับคุณสมบัติการอัปโหลดรูปภาพบนคลาวด์ด้วยreact-dropzoneบน UI

    axios({
        method: 'get',
        url: file[0].preview, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
        responseType: 'blob'
    }).then(function(response){
         var reader = new FileReader();
         reader.readAsDataURL(response.data); 
         reader.onloadend = function() {
             var base64data = reader.result;
             self.props.onMainImageDrop(base64data)
         }

    })

2
สิ่งนี้ใช้ได้กับคำขอข้ามโดเมนหรือไม่ วิดีโอ Twitter มี URL หยด ฉันต้องสามารถรวบรวมวัตถุหยดที่ URL หยดชี้ไป ฉันใช้เรียก API ในเบราว์เซอร์ซึ่งจะให้ฉันผิดพลาดนี้ Refused to connect to 'blob:https://twitter.com/9e00aec3-6729-42fb-b5a7-01f50be302fa' because it violates the following Content Security Policy directive: "connect-src - คุณขอคำแนะนำได้ไหมว่าฉันอาจทำอะไรผิด / ไม่ได้รับ?
gdadsriver

ฉันสามารถใช้ซับเดียวนี้เพื่อให้ได้ผลลัพธ์ที่มีหยดเป็นคุณสมบัติข้อมูล: const result = await axios.get (url, {responseType: "blob"});
Noah Stahl


4

ใช้การดึงข้อมูลเช่นด้านล่าง:

 fetch(<"yoururl">, {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + <your access token if need>
    },
       })
.then((response) => response.blob())
.then((blob) => {
// 2. Create blob link to download
 const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `sample.xlsx`);
 // 3. Append to html page
 document.body.appendChild(link);
 // 4. Force download
 link.click();
 // 5. Clean up and remove the link
 link.parentNode.removeChild(link);
})

คุณสามารถวางบนคอนโซล Chrome เพื่อทดสอบ ไฟล์ที่ดาวน์โหลดด้วย 'sample.xlsx' หวังว่าจะช่วยได้!


ฉันคิดว่า OP ถามเกี่ยวกับการแปลง blob url เป็นไฟล์ / blob จริงแทนที่จะเป็นวิธีอื่น
Abhishek Ghosh

3

น่าเสียดายที่คำตอบของ @ BrianFreud ไม่ตรงกับความต้องการของฉันฉันมีความต้องการที่แตกต่างกันเล็กน้อยและฉันรู้ว่านั่นไม่ใช่คำตอบสำหรับคำถามของ @ BrianFreud แต่ฉันจะทิ้งไว้ที่นี่เพราะมีคนจำนวนมากมาที่นี่ด้วยความต้องการเดียวกันของฉัน ฉันต้องการบางอย่างเช่น 'จะรับไฟล์หรือหยดจาก URL ได้อย่างไร' และคำตอบที่ถูกต้องในปัจจุบันไม่ตรงกับความต้องการของฉันเพราะไม่ใช่ข้ามโดเมน

ฉันมีเว็บไซต์ที่ใช้ภาพจาก Amazon S3 / Azure Storage และที่นั่นฉันเก็บวัตถุที่ตั้งชื่อด้วยตัวบ่งชี้ที่ไม่ซ้ำกัน:

ตัวอย่าง: http: //****.blob.core.windows.net/systemimages/bf142dc9-0185-4aee-a3f4-1e5e95a09bcf

ภาพนี้บางส่วนควรดาวน์โหลดจากอินเทอร์เฟซระบบของเรา เพื่อหลีกเลี่ยงการส่งผ่านทราฟฟิกนี้ผ่านเซิร์ฟเวอร์ HTTP ของฉันเนื่องจากอ็อบเจ็กต์นี้ไม่ต้องการความปลอดภัยใด ๆ ในการเข้าถึง (ยกเว้นโดยการกรองโดเมน) ฉันตัดสินใจที่จะส่งคำขอโดยตรงบนเบราว์เซอร์ของผู้ใช้และใช้การประมวลผลภายในเพื่อตั้งชื่อจริงให้ไฟล์และ ส่วนขยาย.

เพื่อให้บรรลุผลสำเร็จฉันได้ใช้บทความดีๆจาก Henry Algus: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/

1. ขั้นตอนแรก: เพิ่มการสนับสนุนไบนารีใน jquery

/**
*
* jquery.binarytransport.js
*
* @description. jQuery ajax transport for making binary data type requests.
* @version 1.0 
* @author Henry Algus <henryalgus@gmail.com>
*
*/

// use this transport for "binary" data type
$.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();
            }
        };
    }
});

2. ขั้นตอนที่สอง: ส่งคำขอโดยใช้ประเภทการขนส่งนี้

function downloadArt(url)
{
    $.ajax(url, {
        dataType: "binary",
        processData: false
    }).done(function (data) {
        // just my logic to name/create files
        var filename = url.substr(url.lastIndexOf('/') + 1) + '.png';
        var blob = new Blob([data], { type: 'image/png' });

        saveAs(blob, filename);
    });
}

ตอนนี้คุณสามารถใช้ Blob ที่สร้างขึ้นตามที่คุณต้องการในกรณีของฉันฉันต้องการบันทึกลงในดิสก์

3. ทางเลือก: บันทึกไฟล์บนคอมพิวเตอร์ของผู้ใช้โดยใช้ FileSaver

ฉันใช้ FileSaver.js เพื่อบันทึกไฟล์ที่ดาวน์โหลดลงในดิสก์หากคุณต้องการทำสิ่งนั้นให้สำเร็จโปรดใช้ไลบรารี javascript นี้:

https://github.com/eligrey/FileSaver.js/

ฉันคาดหวังว่าสิ่งนี้จะช่วยให้ผู้อื่นมีความต้องการเฉพาะเจาะจงมากขึ้น


1
ObjectURL เป็นไปตามนิยามในท้องถิ่น URL ของวัตถุคือ URL ที่ชี้ไปยังไฟล์บนดิสก์ เนื่องจากไม่มีสิ่งที่เรียกว่า cross-domain objectURL คุณกำลังผสมผสานแนวคิดที่แตกต่างกันสองแนวคิดดังนั้นปัญหาของคุณโดยใช้โซลูชันที่กำหนด
BrianFreud

1
@BrianFreud ฉันเข้าใจแล้วว่าไม่ใช่คำตอบของคำถามนี้ แต่ฉันยังคิดว่ามันเป็นคำตอบที่ดีที่จะออกไปตั้งแต่ฉันมาที่นี่เพื่อหาคำตอบของคำถามที่แตกต่างกันเล็กน้อย 'จะรับไฟล์หรือหยดจาก URL ได้อย่างไร?' หากคุณตรวจสอบคำตอบของคุณเองมี 10 upvotes เกี่ยวกับ 'ไม่สามารถใช้งานได้ในกรณีที่มีคำขอข้ามโดเมน ' มีคนมากกว่า 10 คนมาที่นี่เพื่อค้นหาสิ่งนั้น ฉันตัดสินใจแล้วว่าจะทิ้งไว้ที่นี่
Wagner Bertolini Junior

ปัญหาคือคำตอบของคุณไม่ได้ตอบคำถามนี้โดยเจตนา URL ปกติและ URL ออบเจ็กต์เป็นสองสิ่งที่แตกต่างกันอย่างสิ้นเชิง เกี่ยวกับจำนวนการโหวตเพิ่มขึ้นของ "มันใช้ไม่ได้ในกรณีที่มีคำขอข้ามโดเมน" คุณจะไม่คิดว่าจะอธิบายได้ดีกว่าหรือไม่ว่าทำไมจึงเป็นไปไม่ได้ที่นี่และชี้ไปที่บางแห่งที่แสดงคำตอบสำหรับ URL ปกติมากกว่า มากกว่าความสับสนที่นี่โดยการรวม URL ปกติและ URL ของวัตถุ?
BrianFreud

@BrianFreud อย่าลังเลที่จะแนะนำการแก้ไขคำตอบของฉัน ฉันจะศึกษาเกี่ยวกับเรื่องนี้บางทีฉันอาจเข้าใจผิดว่า "objectURL" คืออะไรกับ "object URL" ... ภาษาอังกฤษไม่ใช่ภาษาแม่ของฉัน ฉันจะทำการวิจัยเกี่ยวกับเรื่องนี้เพื่อให้คำตอบที่ดีขึ้น แต่ฉันคิดว่าเป็นคนอื่น ๆ ที่มาที่นี่เพื่อค้นหาสิ่งที่แตกต่าง ฉันไม่ได้ค้นหา "objectURL" เพื่อมาที่นี่นั่นคือประเด็นของฉันมาก่อน แต่ฉันก็มีคุณเช่นกัน
Wagner Bertolini Junior

2

หากคุณแสดงไฟล์ในผืนผ้าใบคุณยังสามารถแปลงเนื้อหาแคนวาสเป็นวัตถุหยดได้

canvas.toBlob(function(my_file){
  //.toBlob is only implemented in > FF18 but there is a polyfill 
  //for other browsers https://github.com/blueimp/JavaScript-Canvas-to-Blob
  var myBlob = (my_file);
})

2
โปรดทราบว่าว่าไม่จริงให้คุณกลับเดียวกันไฟล์ต้นฉบับ; กำลังสร้างไฟล์ภาพใหม่ได้ทันที เมื่อฉันทดสอบครั้งล่าสุดเมื่อสองสามปีก่อนฉันพบว่าอย่างน้อยใน Chrome ไฟล์รูปภาพใหม่จะไม่ถูกบีบอัดเลย - ฉันมี 10k jpgs เปลี่ยนเป็น 2.5 mb jpgs
BrianFreud
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.