<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="author" content="xgqfrms">
  <meta name="generator" content="VS code">
  <title>Fetch API & Blob File Download & HTML5 Download</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    video {
      width: 70vw;
      height: 300px;
      margin: 30px auto;
    }
  </style>
  <!-- <link rel="stylesheet" href="./index.css"> -->
</head>
<body>
  <header>
    <h1>Fetch API & Blob File Download & HTML5 Download</h1>
    <a href="https://cdn.xgqfrms.xyz/HTML5/Blob/fetch/index.html">https://cdn.xgqfrms.xyz/HTML5/Blob/fetch/index.html</a>
  </header>
  <main>
<!--     <iframe src="https://cdn.xgqfrms.xyz/HTML5/Blob/fetch/index.html" width="100%" height="300"></iframe> -->
    <section>
      <h2>custom HTML5 video download</h2>
      <video id="video" controls width="100%" height="500"
        filename="2020-sh.mp4"
        download="2020-sh.mp4"
        data-url="https://cdn.xgqfrms.xyz/HTML5/Blob/2022-04-07-sh.mp4">
        loading...
      </video>
      <div>
        <a id="video-link" download="2022-sh.mp4">2022-sh.mp4</a>
      </div>
      <img id="img" download="logo.png" />
      <div>
        <a id="img-link" download="logo.png">logo.png</a>
      </div>
      <br>
      <h2>不仅支持 XMLHttpRequest ✅  & 还支持 Fetch API ✅</h2>
      <a href="https://codepen.io/xgqfrms/pen/xxpzGLY">https://codepen.io/xgqfrms/pen/xxpzGLY0</a>
      <p>blob:https:// Blob 文件,通过设置 a 的 download 属性和 href 属性, 是可以下载 ✅</p>
      <p>blob:localhost:// Blob 文件,通过设置 a 的 download 属性和 href 属性, 是可以下载 ✅</p>
    </section>
  </main>
  <footer>
    <p>copyright&copy; xgqfrms 2022</p>
  </footer>
  <!-- js -->
  <!-- <script src="./app.js"></script> -->
</body>
</html>
async function generatorBlobVideo(url, type, dom, link) {
  const headers = {
    responseType: 'arraybuffer',
  };
  // const headers = new Headers({
  //   'Content-Type': 'text/plain',
  //   'X-Custom-Header': 'ProcessThisImmediately',
  // });
  // const headers = new Headers();
  // headers.append('Content-Type', 'text/plain');
  // headers.append('X-Custom-Header', 'ProcessThisImmediately');
  // headers.set('Content-Type', 'text/html');
  // headers.has('X-Custom-Header');
  // headers.get('X-Custom-Header');
  // headers.delete('X-Custom-Header');
  // promise.then(res => res.json()).catch(err => {}).finally(() => {});
  // promise.then(res => res.arrayBuffer()).catch(err => {}).finally(() => {});
  const promise = await fetch(url, {
    // method: 'GET', // *GET, POST, PUT, DELETE, etc.
    // mode: 'cors', // no-cors, *cors, same-origin
    // cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    // credentials: 'same-origin',
    // credentials: 'include',
    method: 'GET',
    // mode: 'no-cors',
    // ❌  A no-cors request makes the response type opaque. Opaque means your frontend JavaScript code can’t see the response body or headers.
    // ✅ 需要设置 代理服务器,解决 CORS 导致 opaque bug 问题
    responseType: 'arraybuffer',
    headers: {
      // 'Accept': type,
      'Content-Type': type,
      // 'Accept': 'video/mp4',
      // 'Content-Type': 'video/mp4',
      // 'Accept': 'application/arraybuffer',
      // 'Content-Type': 'application/arraybuffer',
      // 'Accept': 'application/octet-stream',
      // 'Content-Type': 'application/octet-stream',
      // 'Accept': 'application/json',
      // 'Content-Type': 'application/json',
      // 'Content-Type': 'application/json;charset=utf-8'
      // 'Content-Type': 'application/json',
      // 'Content-Type': 'application/x-www-form-urlencoded',
      // ...headers,
    },
  }).then(res => {
    console.log('fetch.response =', res);
    return res.arrayBuffer();
  }).then(data => {
    // 不仅支持 XMLHttpRequest ✅  & 还支持 Fetch API ✅
    // const buffer = res.arrayBuffer();
    const blob = new Blob(
      [data],
      // [buffer],
      {'type' : type},
    );
    // const file = new File(buffer, 'test');
    const urlBlob = URL.createObjectURL(blob);
    dom.src = urlBlob;
    link.href = urlBlob;
    link.innerText = urlBlob;
  })
  .catch(err => {})
  .finally(() => {});
}

(async function() {
  var type = 'image/png';
  var url = 'https://cdn.xgqfrms.xyz/logo/icon.png';
  var dom = document.querySelector('#img');
  var link = document.querySelector('#img-link');
  // console.log('img link =', link);
  await generatorBlobVideo(url, type, dom, link);
})();

(async function() {
  var type = 'video/mp4';
  var url = 'https://cdn.xgqfrms.xyz/HTML5/Blob/2022-04-07-sh.mp4';
  var dom = document.querySelector('#video');
  var link = document.querySelector('#video-link');
  // console.log('video link =', link);
  setTimeout(() => {
    // await generatorBlobVideo(url, type, dom, link);
    generatorBlobVideo(url, type, dom, link);
  }, 3000);
})();









/*

https://cdn.xgqfrms.xyz/HTML5/Blob/index.html

# fetch set arraybuffer headers

'Content-Type': 'application/json;charset=utf-8'

https://javascript.info/fetch

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

```js

const myHeaders = new Headers();

const myRequest = new Request('flowers.jpg', {
  method: 'GET',
  headers: myHeaders,
  mode: 'cors',
  cache: 'default',
});

fetch(myRequest)
  .then(response => response.blob())
  .then(myBlob => {
    myImage.src = URL.createObjectURL(myBlob);
  });


```


https://developer.mozilla.org/en-US/docs/Web/API/Request/Request

https://developer.mozilla.org/en-US/docs/Web/API/Request/headers

```js

request.blob().then(function(myBlob) {
  // do something with myBlob
});



```

https://developer.mozilla.org/en-US/docs/Web/API/Request/blob

```js
const myArray = new Uint8Array(10);

const request = new Request('/myEndpoint', {
  method: 'POST',
  body: myArray
});

request.arrayBuffer().then(function(buffer) {
  // do something with the buffer sent in the request
});

```

https://developer.mozilla.org/en-US/docs/Web/API/Request/arrayBuffer

```js

  const promise = fetch(url, {
    method: 'GET',
    responseType: 'arraybuffer',
    headers: {
      // 'Accept': 'video/mp4',
      'Content-Type': 'video/mp4',
      // 'Accept': 'application/json',
      // 'Content-Type': 'application/json;charset=utf-8'
      // ...headers,
    },
  });
  // promise.then(res => res.json()).catch(err => {}).finally(() => {});
  // promise.then(res => res.arrayBuffer()).catch(err => {}).finally(() => {});
  
```


https://developer.mozilla.org/en-US/docs/Web/API/Response/arrayBuffer


https://blog.csdn.net/WU5229485/article/details/85219165

https://www.w3cschool.cn/fetch_api/fetch_api-5uen2ll8.html
https://m.w3cschool.cn/fetch_api/fetch_api-5uen2ll8.html



*/
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.