简体   繁体   English

如何从内容处置中获取文件名

[英]How to get file name from content-disposition

I downloaded a file as response of ajax.我下载了一个文件作为 ajax 的响应。 How to get the file name and file type from content-disposition and display thumbnail for it.如何从content-disposition获取文件名和文件类型并为其显示缩略图。 I got many search results but couldn't find right way.我得到了很多搜索结果,但找不到正确的方法。

$(".download_btn").click(function () {
  var uiid = $(this).data("id2");

  $.ajax({
    url: "http://localhost:8080/prj/" + data + "/" + uiid + "/getfile",
    type: "GET",
    error: function (jqXHR, textStatus, errorThrown) {
      console.log(textStatus, errorThrown);
    },
    success: function (response, status, xhr) {
      var header = xhr.getResponseHeader('Content-Disposition');
      console.log(header);     
    }
});

Console output:控制台输出:

inline; filename=demo3.png

Here is how I used it sometime back.这是我以前使用它的方式。 I'm assuming you are providing the attachment as a server response.我假设您将附件作为服务器响应提供。

I set the response header like this from my REST service response.setHeader("Content-Disposition", "attachment;filename=XYZ.csv");我从我的 REST 服务response.setHeader("Content-Disposition", "attachment;filename=XYZ.csv");设置这样的响应头response.setHeader("Content-Disposition", "attachment;filename=XYZ.csv");

function(response, status, xhr){
    var filename = "";
    var disposition = xhr.getResponseHeader('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) { 
          filename = matches[1].replace(/['"]/g, '');
        }
    }
}

EDIT: Editing the answer to suit your question- use of the word inline instead of attachment编辑:编辑答案以适合您的问题 - 使用词inline而不是attachment

function(response, status, xhr){
    var filename = "";
    var disposition = xhr.getResponseHeader('Content-Disposition');
    if (disposition && disposition.indexOf('inline') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) { 
          filename = matches[1].replace(/['"]/g, '');
        }
    }
}

More here 更多在这里

This is an improvement on marjon4's answer.这是对 marjon4 答案的改进。

A much simplified way to the selected answer would be to use split like this;选择答案的一种更简单的方法是使用 split ;

var fileName = xhr.getResponseHeader('content-disposition').split('filename=')[1].split(';')[0];

Note: This solution may not work as expected if your file name itself contains a semi-colon (;)注意:如果您的文件名本身包含分号 (;),则此解决方案可能无法按预期工作

或者只是:

var fileName = xhr.getResponseHeader('Content-Disposition').split("filename=")[1];

In my case the header looks like this:在我的情况下,标题如下所示:

attachment; filename="test-file3.txt"

Therefore I was able to extract the filename pretty easily with a named group regexp:因此,我能够使用命名组正则表达式很容易地提取文件名:

const regExpFilename = /filename="(?<filename>.*)"/;

const filename: string | null = regExpFilename.exec(contentDispositionHeader)?.groups?.filename ?? null;

I know I'm slightly off topic here as OP doesn't have the quotes around the filename but still sharing in case someone comes across the same pattern as I just did我知道我在这里有点偏离主题,因为 OP 没有在文件名周围加上引号,但仍然共享以防有人遇到与我刚刚做的相同的模式

Try this solution:试试这个解决方案:

var contentDisposition = xhr.getResponseHeader('Content-Disposition');
var startIndex = contentDisposition.indexOf("filename=") + 10; // Adjust '+ 10' if filename is not the right one.
var endIndex = contentDisposition.length - 1; //Check if '- 1' is necessary
var filename = contentDisposition.substring(startIndex, endIndex);
console.log("filename: " + filename)

有一个 npm 包可以完成这项工作: content-disposition

If you want to get the filename and support both weird url encoded UTF-8 and the ascii headers, you can use something like this如果你想获得文件名并支持奇怪的 url 编码的 UTF-8 和 ascii 头,你可以使用这样的东西

public getFileName(disposition: string): string {
    const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; ?|$)/;
    const asciiFilenameRegex = /filename=(["']?)(.*?[^\\])\1(?:; ?|$)/;

    let fileName: string = null;
    if (utf8FilenameRegex.test(disposition)) {
      fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
    } else {
      const matches = asciiFilenameRegex.exec(disposition);
      if (matches != null && matches[2]) {
        fileName = matches[2];
      }
    }
    return fileName;
}

A couple of notes:一些注意事项:

  1. this will take the value of the UTF-8 filename, if set, over the ascii name这将采用 UTF-8 文件名的值(如果已设置)覆盖 ascii 名称
  2. your browser may further alter the name to replace certain characters, like " , with _ (Chrome)您的浏览器可能会进一步更改名称以替换某些字符,例如" ,使用_ (Chrome)
  3. the ascii pattern works best for quoted file names, but supports unquoted values. ascii 模式最适用于带引号的文件名,但支持不带引号的值。 In that case it treats all text after the filename= and before the either the next ;在这种情况下,它会处理filename=和下一个;之前的所有文本; or the end of the header value as the file name.或标题值的结尾作为文件名。

MDN Content Disposition Header MDN 内容处置标头

If you are not working with multipart body then you can use this function.如果您不使用多部分主体,则可以使用此功能。 It extracts the filename from the Content-Disposition header value (string like: inline; filename=demo3.png ) and decodes as needed.它从 Content-Disposition 标头值(字符串如: inline; filename=demo3.png )中提取文件名并根据需要进行解码。

const getFileNameFromContentDisposition = disposition => { 
    if (disposition
        && (disposition.startsWith('attachment') || disposition.startsWith('inline'))
    ) {
        let filename = disposition.startsWith('attachment')
            ? disposition.replace("attachment;", "")
            : disposition.replace("inline;", ""); //replaces first match only
        filename = filename.trim();
        if (filename.startsWith("filename=")) {
            filename = filename.replace("filename=", "");
            filename = filename.slice(1, filename.length - 1); //remove quotes
        } else if (filename.startsWith("filename*=")) {
            filename = filename.replace("filename*=", "")
                .split("''").slice(1).join("''"); //remove encoding and ''
            filename = decodeURIComponent(filename);
        }
        return filename;
    }
}

The result of the function can be split into name and extension as follows:函数的结果可以拆分为名称和扩展名,如下所示:

let name = getFileNameFromContentDisposition("inline; filename=demo.3.png").split(".");
let extension = name[name.length - 1];
name = name.slice(0, name.length - 1).join(".");
console.log(name); // demo.3
console.log(extension); //png

You can display thumbnail, for example, using svg:例如,您可以使用 svg 显示缩略图:

let colors = {"png": "red", "jpg": "orange"};
//this is a simple example, you can make something more beautiful
let createSVGThumbnail = extension => `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20">
    <rect x="0" y="0" width="18" height="20" fill = "#FAFEFF"/>
    <rect x="0" y="7" width="18" height="6" stroke="${colors[extension] || "blue"}" fill = "${colors[extension] || "blue"}"/>
    <text stroke = "white" fill = "white" font-size = "6" x = "0" y = "12.5" textLength = "18">${extension.toUpperCase()}</text>
</svg>`;

...

//You can use it as HTML element background-image
let background = "data:image/svg+xml;base64," + btoa(new TextDecoder().decode(createSVGThumbnail("png"))); 

(file gets saved in binary format in the browser. the filename is in client's Network/header/Content-Disposition, we need to fetch the filename) (文件在浏览器中以二进制格式保存。文件名在客户端的 Network/header/Content-Disposition 中,我们需要获取文件名)

In Server-side code:
node js code-
    response.setHeader('Access-Control-Expose-Headers','Content-Disposition');
    response.download(outputpath,fileName);   

In client-side code:
1)appComponent.ts file
import { HttpHeaders } from '@angular/common/http';
this.reportscomponentservice.getReportsDownload(this.myArr).subscribe((event: any) => {
 var contentDispositionData= event.headers.get('content-disposition');
 let filename = contentDispositionData.split(";")[1].split("=")[1].split('"')[1].trim()
 saveAs(event.body, filename); 
});

2) service.ts file
import { HttpClient, HttpResponse } from '@angular/common/http';
getReportsDownload(myArr): Observable<HttpResponse<Blob>> {
 console.log('Service Page', myArr);
 return this.http.post(PowerSimEndPoints.GET_DOWNLOAD_DATA.PROD, myArr, {
  observe: 'response',
  responseType: 'blob'
 });
}

Didn't find any response on stackoverflow in my case. 在我的情况下没有在stackoverflow上找到任何响应。 I receive a content-disposition like that: inline; 我收到了这样的内容处理: 内联; filename*=UTF-8''Dossier%20de%20diagnostic%20technique.pdf 文件名* = UTF-8''Dossier%20de%20diagnostic%20technique.pdf

I modified the regex to deal with an UTF-8 string if present : var regex = /filename[^;=\\n] =(UTF-8(['"] ))?(.*)/; 我修改了正则表达式来处理UTF-8字符串(如果存在): var regex = / filename [^; = \\ n] =(UTF-8(['“] ))?(。*)/;

And here is my function : 这是我的功能:

function getFileNameByContentDisposition(contentDisposition){
    var regex = /filename[^;=\n]*=(UTF-8(['"]*))?(.*)/;
    var matches = regex.exec(contentDisposition);
    var filename;

    if (matches != null && matches[3]) { 
      filename = matches[3].replace(/['"]/g, '');
    }

    return decodeURI(filename);
}

EDIT : I didn't test it that much. 编辑:我没有那么多测试。 Don't forget to wrap it with a try / catch in a NodeJS code. 不要忘记在NodeJS代码中使用try / catch包装它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法从后端响应获取“ Content-Disposition” - Not able to get the `Content-Disposition` from backend response 解压一个内容处理的 gzip 文件:附件 - Unpack a gzip file that is content-disposition: attachment XMLHttpRequest 是否阻止了 Content-Disposition 附件? - Is Content-Disposition attachment blocked from XMLHttpRequest? 如何纠正内容配置错误 - How to correct content-disposition error 使用angular-file-upload从请求正文中删除Content-Disposition和Content-Type - Remove Content-Disposition and Content-Type from request body using angular-file-upload Java / Javascript读取内容-处置文件内容 - Java/Javascript read content-disposition file content 从 Rest API 响应内容处置输出 [Object, Object] 下载 javascript 中的 excel 文件 - Download excel file in javascript from Rest API response content-disposition outputs [Object, Object] 使用symfony2从邮件Multipart(Content-Disposition:form-data)获取数据 - Get Datas from post Multipart (Content-Disposition: form-data) with symfony2 使用ng-file-upload和angularjs进行内容处理 - Content-Disposition with ng-file-upload and angularjs 无法在Angular4 GET响应中查看“Content-Disposition”标头 - Unable to view 'Content-Disposition' headers in Angular4 GET response
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM