问题描述

下载文件,返回的对象为blob。
框架封装了所有的异常,不管后台处理正确与否,http的状态都为200. 后台想把异常信息传递给前台,通过设置header方式,代码如下:

#HttpHeader, Resource, ResponseEntity都是spring提供实现
HttpHeader headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.add("charset", "UTF-8");
headers.add("file-name", "自己定义的文件名称");
headers.add("error-message", "后台处理的异常信息");

Resource resource = new InputStreamResource(fileInputStream);
return ReponseEntity.ok().headers(headers).body();

但是前端并没有接到"file-name"和"error-message"的header。
后来发现,是因为跨域不支持用户自定义header。

默认支持的header

Cache-Control

Cache-Control 通用消息头字段,被用于在http请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。
支持的指令:

header

指令

描述

Cache-control

must-revalidate

一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。

Cache-control

no-cache

在发布缓存副本之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)。

Cache-control

no-store

缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。

Cache-control

no-transform

不得对资源进行转换或转变。

Cache-control

public

表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存,即使是通常不可缓存的内容。

Cache-control

private

表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。私有缓存可以缓存响应内容,比如:对应用户的本地浏览器。

Cache-control

proxy-revalidate

与must-revalidate作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略。

Cache-Control

max-age=

设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间。

Cache-control

s-maxage=

覆盖max-age或者Expires头,但是仅适用于共享缓存(比如各个代理),私有缓存会忽略它。

Content-Language

Content-Language 是一个 entity header (实体消息首部),用来说明访问者希望采用的语言或语言组合,这样的话用户就可以根据自己偏好的语言来定制不同的内容。

Content-Length

Content-Length 是一个实体消息首部,用来指明发送给接收方的消息主体的大小,即用十进制数字表示的八位元组的数目。

Content-Type

在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。
org.springframework.http.MediaType里面列举了大部分的类型。
语法:

Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something

type大分类:

  • application
  • audio
  • example
  • font
  • image
  • model
  • text
  • video

常用media-type:

  • application/octet-stream 二进制文件的默认值
  • text/plain 文档文件
  • text/css css文件
  • text/html html文件
  • text/javascript js文件
  • multipart/form-data 表单

Expires

Expires 响应头包含日期/时间, 即在此时候之后,响应过期。
如果在Cache-Control响应头设置了 “max-age” 或者 “s-max-age” 指令,那么 Expires 头会被忽略。

Last-Modified

Last-Modified是一个响应首部,其中包含源头服务器认定的资源做出修改的日期及时间。
它通常被用作一个验证器来判断接收到的或者存储的资源是否彼此一致。

Pragma

Pragma 是一个在 HTTP/1.0 中规定的通用首部,这个首部的效果依赖于不同的实现,所以在“请求-响应”链中可能会有不同的效果。

Pragma: no-cache

添加用户自定义header:Access-Control-Expose-Headers

后端源码:

@GetMapping(value = "/download/file")
public ResponseEntity<Resource> download(HttpServletResponse response){
    response.addHeader("Access-Control-Expose-Headers", "file-name, error-message");
    #HttpHeader, Resource, ResponseEntity都是spring提供实现
    HttpHeader headers = new HttpHeaders();
    headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
    headers.add("Pragma", "no-cache");
    headers.add("Expires", "0");
    headers.add("charset", "UTF-8");
    headers.add("file-name", "自己定义的文件名称");
    headers.add("error-message", "后台处理的异常信息");
    
    Resource resource = new InputStreamResource(fileInputStream);
    return ReponseEntity.ok().headers(headers).body();
}

前端代码:

axios({
        mehtod: GET,
        url: download/file,
        params: {},
        headers: {
            'Content-Type': 'applicaton/x-www-form-urlencoded',
            'token': 'access control info token'
            ...
        },
        responseType:'blob'
    }).then(res => {
        const fileName = res.headers['file-name']
        const errorMessage = res.headers['error-message']
        if (errorMessage) {
            this.message.error('错误信息:' + errorMessage)
        } else {
            ...
        }
    })