来自浏览器的 GET 请求可以将文件下载到本地,但 XMLHttpRequest Javascript 脚本无法下载文件
GET request from browser works to download file to local but XMLHttpRequest Javascript script does not download file
我在使用 XMLHttpRequest 时遇到了问题 我想,当我导航到 localhost/dashboard/downloadfile?file-name=hw3.txt 时,文件会在本地下载,但是如果我使用函数 checkDownload() 来启动一个XMLHttpRequest 文件未下载。
这是我的客户端代码:
function checkDownload() {
const filename = "hw3.txt";
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open('GET', `/dashboard/downloadfile?file-name=${ filename }`);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
}
}
}
xhr.send();
}
然后这是我的服务器代码:
app.get('/dashboard/downloadfile', requiresLogin, (req, res) => {
const userid = req.user.id;
const filename = req.query['file-name'];
db.getFileKey([userid, filename], (keyres) => {
const params = {
Bucket: S3_BUCKET,
Key: keyres.rows[0].filekey,
};
res.setHeader('Content-disposition', `attachment; filename=${ filename }`);
res.setHeader('Content-type', `${ mime.getType(keyres.rows[0].filetype) }`);
s3.getObject(params, (awserr, awsres) => {
if(awserr) console.log(awserr);
else console.log(awsres);
}).createReadStream().pipe(res);
});
});
您正在从服务器返回一个 blob,因此为了下载您需要在 xhr.status === 200
.
时执行某些操作
像这样:
...
if(xhr.status === 200) {
var fileUrl = URL.createObjectURL(xhr.responseText)
window.location.replace(fileUrl)
}
...
要下载具有 URL 的内容,您可以使用 a
标签的 download
属性:
<a download="something.txt" href="https://google.com">Download Google</a>
如果您使用 xhr.responseType = "blob"
,您必须执行以下操作:
function checkDownload() {
const filename = "hw3.txt";
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
var reader = new FileReader();
reader.readAsArrayBuffer(xhr.response);
reader.addEventListener("loadend", function() {
var a = new Int8Array(reader.result);
console.log(JSON.stringify(a, null, ' '));
});
}
}
}
xhr.send();
}
checkDownload()
但是该代码不会下载文件。
我成功了。我没有尝试从 s3.getObject()
创建一个读取流,而是在服务器上生成了一个带符号的 url 到 s3 object 并将其返回给客户端,然后使用 'a' html 元素与 element.href = signedRequest
并使用 javascript 单击该元素。我 运行 遇到的新问题是我无法找到一种方法来设置 s3 object 最初上传时的元数据,我需要手动更改个人的元数据s3 object 通过 aws 控制台,因此它具有 header Content-Disposition: attachment; filename=${ filename }
.
更改客户端代码:
function initDownload(filename) {
const xhr = new XMLHttpRequest();
xhr.open('GET', `/sign-s3-get-request?file-name=${ filename }`);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
startDownload(response.signedRequest, response.url);
}
}
}
xhr.send();
}
function startDownload(signedRequest, url) {
var link = document.createElement('a');
link.href = signedRequest;
link.setAttribute('download', 'download');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
更改服务器代码:
app.get('/sign-s3-get-request', requiresLogin, (req, res) => {
const userid = req.user.id;
const filename = req.query['file-name'];
db.getFileKey([userid, filename], (keyres) => {
const s3Params = {
Bucket: S3_BUCKET,
Key: keyres.rows[0].filekey,
Expires: 60,
};
s3.getSignedUrl('getObject', s3Params, (err, data) => {
if (err) {
// eslint-disable-next-line
console.log(err);
res.end();
}
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${ keyres.rows[0].filekey }`,
};
res.write(JSON.stringify(returnData));
res.end();
});
});
});
我在使用 XMLHttpRequest 时遇到了问题 我想,当我导航到 localhost/dashboard/downloadfile?file-name=hw3.txt 时,文件会在本地下载,但是如果我使用函数 checkDownload() 来启动一个XMLHttpRequest 文件未下载。
这是我的客户端代码:
function checkDownload() {
const filename = "hw3.txt";
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open('GET', `/dashboard/downloadfile?file-name=${ filename }`);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
}
}
}
xhr.send();
}
然后这是我的服务器代码:
app.get('/dashboard/downloadfile', requiresLogin, (req, res) => {
const userid = req.user.id;
const filename = req.query['file-name'];
db.getFileKey([userid, filename], (keyres) => {
const params = {
Bucket: S3_BUCKET,
Key: keyres.rows[0].filekey,
};
res.setHeader('Content-disposition', `attachment; filename=${ filename }`);
res.setHeader('Content-type', `${ mime.getType(keyres.rows[0].filetype) }`);
s3.getObject(params, (awserr, awsres) => {
if(awserr) console.log(awserr);
else console.log(awsres);
}).createReadStream().pipe(res);
});
});
您正在从服务器返回一个 blob,因此为了下载您需要在 xhr.status === 200
.
像这样:
...
if(xhr.status === 200) {
var fileUrl = URL.createObjectURL(xhr.responseText)
window.location.replace(fileUrl)
}
...
要下载具有 URL 的内容,您可以使用 a
标签的 download
属性:
<a download="something.txt" href="https://google.com">Download Google</a>
如果您使用 xhr.responseType = "blob"
,您必须执行以下操作:
function checkDownload() {
const filename = "hw3.txt";
const xhr = new XMLHttpRequest();
xhr.responseType = "blob";
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
var reader = new FileReader();
reader.readAsArrayBuffer(xhr.response);
reader.addEventListener("loadend", function() {
var a = new Int8Array(reader.result);
console.log(JSON.stringify(a, null, ' '));
});
}
}
}
xhr.send();
}
checkDownload()
但是该代码不会下载文件。
我成功了。我没有尝试从 s3.getObject()
创建一个读取流,而是在服务器上生成了一个带符号的 url 到 s3 object 并将其返回给客户端,然后使用 'a' html 元素与 element.href = signedRequest
并使用 javascript 单击该元素。我 运行 遇到的新问题是我无法找到一种方法来设置 s3 object 最初上传时的元数据,我需要手动更改个人的元数据s3 object 通过 aws 控制台,因此它具有 header Content-Disposition: attachment; filename=${ filename }
.
更改客户端代码:
function initDownload(filename) {
const xhr = new XMLHttpRequest();
xhr.open('GET', `/sign-s3-get-request?file-name=${ filename }`);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
startDownload(response.signedRequest, response.url);
}
}
}
xhr.send();
}
function startDownload(signedRequest, url) {
var link = document.createElement('a');
link.href = signedRequest;
link.setAttribute('download', 'download');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
更改服务器代码:
app.get('/sign-s3-get-request', requiresLogin, (req, res) => {
const userid = req.user.id;
const filename = req.query['file-name'];
db.getFileKey([userid, filename], (keyres) => {
const s3Params = {
Bucket: S3_BUCKET,
Key: keyres.rows[0].filekey,
Expires: 60,
};
s3.getSignedUrl('getObject', s3Params, (err, data) => {
if (err) {
// eslint-disable-next-line
console.log(err);
res.end();
}
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${ keyres.rows[0].filekey }`,
};
res.write(JSON.stringify(returnData));
res.end();
});
});
});