RHa*_*ris 12 javascript fetch-api
在我的 javascript 客户端中,我使用 fetch 调用服务器来检索服务器生成的文件。我正在使用以下客户端代码:
var _url = "";
var initParms = {
method: "GET",
mode: 'cors'
}
fetch(_url, initParms)
.then(response => {
if(response.ok){
alert(response.headers.get("content-disposition"));
return response.blob();
}
throw new Error("Network response was not OK.");
})
.then(blob => {
var url = new URL.createObjectURL(blob);
})
Run Code Online (Sandbox Code Playgroud)
这实际上工作得很好。但是,服务器会为该文件生成一个文件名,并将其作为 content-disposition 标头的一部分包含在响应中。
我需要使用服务器生成的文件名将此文件保存到用户的机器上。在 Postman 中,我实际上可以看到响应的内容处置标头设置为:Content-Disposition: attachment;filename=myfilename.txt。
我试图从响应中读取内容配置(请参阅我的 js 代码中的警报),但我总是得到 null(即使相同的响应显示了 Postman 中的内容配置)。
难道我做错了什么?有没有办法使用 fetch 响应来检索文件名?有没有更好的方法从服务器获取文件名和文件?
PS 这是我返回文件的服务器端代码:
控制器动作
public IHttpActionResult GetFile(){
return new FileResult("myfilename.txt","Hello World!");
}
Run Code Online (Sandbox Code Playgroud)
文件结果类
public class FileResult : IHttpActionResult
{
private string _fileText = "";
private string _fileName = "";
private string _contentType = "";
public FileResult(string name, string text)
{
_fileText = text;
_fileName = name;
_contentType = "text/plain";
}
public Task<HttpResponseMessage> ExecuteActionAsync(CancellationToken token)
{
Stream _stream = null;
if (_contentType == "text/plain")
{
var bytes = Encoding.Unicode.GetBytes(_fileText);
_stream = new MemoryStream(bytes);
}
return Task.Run(() =>
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(_stream),
};
response.Content.Headers.ContentType =
new MediaTypeHeaderValue(_contentType);
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment")
{
FileName = _fileName
};
return response;
}, token);
Run Code Online (Sandbox Code Playgroud)
编辑
我的问题是专门关于 fetch 而不是 ajax api。此外,在我的代码中,我表明我已经从响应中读取标题,与建议答案中显示的已接受答案完全相同。但是,正如我在帖子中所述,此解决方案不适用于 fetch。
RHa*_*ris 22
所以,在发布这个问题后不久,我在 Github 上遇到了这个问题。这显然与使用 CORS 有关。
建议的解决方法是添加Access-Control-Expose-Headers:Content-Disposition到服务器上的响应标头。
这有效!
ygl*_*odt 16
您可以从内容处置标头中提取文件名,如下所示:
let filename = '';
fetch(`/url`, { headers: { Authorization: `Bearer ${token}` }}).then((res) => {
const header = res.headers.get('Content-Disposition');
const parts = header!.split(';');
filename = parts[1].split('=')[1];
return res.blob();
}).then((blob) => {
// Use `filename` here e.g. with file-saver:
// saveAs(blob, filename);
});
Run Code Online (Sandbox Code Playgroud)
Chr*_*ris 14
决定发布此内容,因为接受的答案(尽管对很多人有帮助)实际上并没有回答原始问题:
\n\n\n“如何从使用 JavaScript Fetch API 下载的文件中获取文件名?” 。
\n
人们可以阅读filename(如下例所示),并使用与此类似的方法下载文件(downloadjs该文章中推荐的库不再维护;因此,我不建议使用它)。下面还考虑了其中filename包含 unicode 字符(即-, !, (, )等)并因此以例如(有关更多详细信息,请参阅此处utf-8)的形式出现(编码)的情况。在这种情况下,该函数用于解码.filename*=utf-8\'\'Na%C3%AFve%20file.txtdecodeURIComponent()filename
const url =\'http://127.0.0.1:8000/\'\nfetch(url)\n .then(res => {\n const disposition = res.headers.get(\'Content-Disposition\');\n filename = disposition.split(/;(.+)/)[1].split(/=(.+)/)[1];\n if (filename.toLowerCase().startsWith("utf-8\'\'"))\n filename = decodeURIComponent(filename.replace(/utf-8\'\'/i, \'\'));\n else\n filename = filename.replace(/[\'"]/g, \'\');\n return res.blob();\n })\n .then(blob => {\n var url = window.URL.createObjectURL(blob);\n var a = document.createElement(\'a\');\n a.href = url;\n a.download = filename;\n document.body.appendChild(a); // append the element to the dom\n a.click();\n a.remove(); // afterwards, remove the element \n });\nRun Code Online (Sandbox Code Playgroud)\n如果您正在进行跨源请求,请确保在服务器端设置Access-Control-Expose-Headers响应标头,以便公开Content-Disposition标头;否则,filename将无法通过 JavaScript 在客户端访问(请参阅此处的更多文档)。例如(摘自这个答案):
headers = {\'Access-Control-Expose-Headers\': \'Content-Disposition\'}\nreturn FileResponse("Na\xc3\xafve file.txt", filename="Na\xc3\xafve file.txt", headers=headers)\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
12356 次 |
| 最近记录: |