인증이 된 사용자만 파일 다운로드가 가능해야하는 상황이라서 일반적인 a href를 쓸 수 없었다. 이런 경우 이런 식으로 파일 다운로드를 진행해야하는 것 같았다.
간단해보이는 소스지만, 이 조합을 찾아내기까지 하루이상의 시간이 소요되었기 때문에 다음에는 헤매지 않기 위해 기록해둔다.
1. Express
import { join } from 'path';
...
router.get('/subpath/:id', async (req, res, next) => {
const id = req.params.id;
const filePath = join(__dirname, `서버에 저장된하위경로`);
const filename = '파일명.확장자';
// 1안
res.setHeader('Content-Disposition', `attachment; filename=다른파일명가능`); // 필수
res.sendFile(filePath + filename);
// 2안
res.download(filePath + filename); // 서버에 저장된 파일명으로만 가능
// 3안
res.setHeader('Content-Disposition', `attachment; filename=다른파일명가능`); // 필수
const stream = fs.createReadStream(filePath + filename);
stream.pipe(res);
});
출처: 불특정 다수
2. Front
const authHeader = 'token값'
const url = `/api/subpath/${id}`
let filename = '' // 서버에서 보내는 파일명이 담길 변수
fetch(url, { headers: { 'X-Auth-Token': authHeader } })
.then((response) => {
if (!response.ok) {
throw Error(response.statusText)
}
const header = response.headers.get('Content-Disposition')
const parts = header.split(';')
filename = parts[1].split('=')[1].replaceAll('"', '')
return response.blob()
})
.then((blob) => {
if (blob != null) {
var url = window.URL.createObjectURL(blob)
var a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
a.remove()
}
})
.catch((err) => {
console.log(err)
})
front의 경우 이거 말고도 new ReadableStream에 new Response 동원해서 하는 복잡한 소스도 있었는데 위가 더 심플하고 속도도 체감될 정도로 빨라서 이 걸로 낙찰했다.
'Javascript' 카테고리의 다른 글
정렬 sort (0) | 2021.04.01 |
---|---|
jQuery to VanillaJS (0) | 2021.03.16 |
키보드를 이용한 Input text 포커스 이동 (0) | 2021.03.15 |
String to Date / Date to String (0) | 2020.12.17 |
숫자에 콤마와 언콤마를 편하게 (0) | 2016.06.27 |