Berbagi teknologi

Cara mengunduh file front-end

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Metode 1: Unduh langsung dengan tag

<a href="链接" >下载</a>
  • 1

Tautan file (biasanya file di server). Tautan ini biasanya dimasukkan di bilah alamat untuk melihat pratinjau, bukan untuk mengunduh lampiran.

Jika Anda ingin mengubahnya menjadi unduhan lampiran, Anda dapat memilih salah satu dari dua metode berikut:
1. Pemrosesan backend, tambahkan header respons ke backend

res.setHeader('Content-Dispostion', 'attachment', 'name.pdf')

  • 1
  • 2

2. Tambahkan atribut download pada tag a

<a href="链接" download="文件名" >下载</a>
  • 1

Kerugian dari metode satu:

Kekurangan: Saat menggunakan tag a untuk mengunduh file dalam JavaScript, unduhan browser dipicu langsung melalui peristiwa klik dari tag a. Header permintaan tidak dapat disetel karena ini adalah permintaan GET sederhana. Jika pengunduhan file ini memerlukan pembawaan token, maka tag a tidak akan efektif (tag a tidak dapat membawa token) dan akan menjadi pratinjau.
Solusi: Tag a dapat membawa cookie, jadi ada solusi lain Sebelum mengunduh file, kirimkan permintaan untuk mendapatkan token sementara dan membawanya melalui cookie. Unduhan tag a adalah unduhan streaming, yang akan membuat file server seperti air mengalir. Disimpan ke disk lokal, sehingga hasil download dapat dilihat langsung dan file tidak akan di-cache di browser.

Metode judul dua: Gunakan XMLHttpRequest atau Ambil permintaan API.

Tulis metode untuk mendownload (intinya tetap gunakan tag a untuk mendownload)
Metode ini dapat berupa permintaan ajax, yang dapat membawa token, lalu mengonversi file server yang diminta menjadi blob, membuat tag a untuk diunduh, membuat elemen tautan virtual, dan menyimulasikan klik untuk mengunduh. Metode ini akan menempati thread front-end.


import fetch from 'isomorphic-fetch';
const exportFile = (url, options) => {
  const projectId = sessionStorage.getItem(PROJECT_ID);
  const downLoadURL = projectId ? BATCH_ACTION_URL_PREFIX.V2 : BATCH_ACTION_URL_PREFIX.V1;
  const defaultOptions = {
    credentials: 'same-origin',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE'
  ) {
    const projectId = sessionStorage.getItem(PROJECT_ID);
    const appId = sessionStorage.getItem(APP_ID);
    const shopId = sessionStorage.getItem(SHOP_ID);
    const params = {};
    projectId && Object.assign(params, { projectId });
    appId && Object.assign(params, { appId });
    shopId && Object.assign(params, { shopId });
    newOptions.body = { ...newOptions.body, ...params };
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      };
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      };
    }
  }
  const token = window.localStorage.getItem(TOKEN);
  if (token) {
    newOptions.headers = {
      'X-Authorization': `Bearer ${token}`,
      ...newOptions.headers,
    };
  }
  const lang = localStorage.getItem(LOCALE_KEY);
  if (lang) {
    newOptions.headers = {
      'Accept-Language': lang,
      ...newOptions.headers,
    };
  }
  const requestURL = `${downLoadURL}/${url}`;
  return request(requestURL, newOptions).then(res => {
    let filename;
    if (res.headers) {
      filename = (
        res.headers.get('Content-Disposition') || res.headers.get('content-disposition')
      ).split('attachment;filename=')[1];
    }
    if (res.blob) {
      res.blob().then(blob => {
        var alink = document.createElement('a');
        alink.style.display = 'none';
        alink.target = '_blank';
        if (window.navigator && window.navigator.msSaveOrOpenBlob) {
          // 兼容IE/Edge
          window.navigator.msSaveOrOpenBlob(blob, filename);
        } else {
          alink.href = window.URL.createObjectURL(blob);
          alink.download = filename;
        }
        document.body.appendChild(alink);
        alink.click();
        URL.revokeObjectURL(alink.href); // 释放URL 对象
        document.body.removeChild(alink);
      });
      return res;
    } else {
      if (res.code === 0) {
        return res;
      } else {
        message.warning(res.message);
      }
    }
  });
};

export default exportFile;


export default function request(url: string, options: Object) {
  const defaultOptions = {
    credentials: 'same-origin',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (
    newOptions.method === 'POST' ||
    newOptions.method === 'PUT' ||
    newOptions.method === 'DELETE' ||
    newOptions.method === 'PATCH'
  ) {
    if (!(newOptions.body instanceof FormData)) {
      newOptions.headers = {
        Accept: 'application/json',
        'Content-Type': 'application/json; charset=utf-8',
        ...newOptions.headers,
      };
      newOptions.body = JSON.stringify(newOptions.body);
    } else {
      // newOptions.body is FormData
      newOptions.headers = {
        Accept: 'application/json',
        ...newOptions.headers,
      };
    }
  }

  return fetch(url, newOptions).then(response => checkStatus(response, url, options));
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120

Kerugian dari metode dua:

**Jika filenya kecil, tidak apa-apa. Jika filenya besar, Anda akan mengklik untuk mendownload, tetapi tidak akan ada respon. Download akan muncul setelah beberapa menit sisi server menjadi gumpalan (res.blob () Butuh waktu yang sangat lama) sebelum pengunduhan streaming tag a dilakukan (hanya di sini refleksi interaktif pengunduhan mulai muncul di halaman)