返回

Vue-Element-Admin拦截器和Hyperf后端中间件修改,使用Header头内容作为下载的文件名踩坑记录

前端

好的,请看由AI螺旋创作器创作的文章:

正文

前言&回顾

最近在使用vue-element-admin开发后台,可以看看之前的文章心路历程:

正文开始

最近在项目中遇到一个需求,需要将服务器端导出的文件重命名,并使用文件名中的信息作为文件名。

经过一番调研,我发现可以通过修改vue-element-admin拦截器和Hyperf后端中间件来实现这一需求。

修改vue-element-admin拦截器

首先,我们需要修改vue-element-admin的拦截器。

在项目中,我们可以找到一个名为src/plugins/axios.js的文件,这个文件是用来配置axios的。

// Axios plugin setup
const axios = axiosCreate(process.env.VUE_APP_API_BASE_URL)

axios.interceptors.request.use(
  config => {
    config.headers['Content-Type'] = 'application/json'
    // Do something before request is sent
    return config
  },
  error => {
    // Do something with request error
    return Promise.reject(error)
  }
)

axios.interceptors.response.use(
  response => {
    // Do something before response is sent
    return response
  },
  error => {
    // Do something with response error
    return Promise.reject(error)
  }
)

export default function (app) {
  app.config.globalProperties.$axios = axios
}

在这个文件中,我们可以看到有一个名为interceptors.response.use的拦截器。

我们可以通过这个拦截器来修改服务器端返回的响应数据。

interceptors.response.use拦截器中,我们可以添加如下代码:

// 如果是下载文件,则重命名文件名
if (response.headers['content-type'].indexOf('application/octet-stream') !== -1) {
  const filename = response.headers['content-disposition'].split('filename=')[1]
  response.data = {
    name: decodeURIComponent(filename),
    data: response.data
  }
}

// 返回修改后的响应数据
return response

这段代码的作用是,如果服务器端返回的是一个文件,则将文件重命名为content-disposition头中的文件名。

修改Hyperf后端中间件

修改完vue-element-admin的拦截器后,我们还需要修改Hyperf后端中间件。

在项目中,我们可以找到一个名为config/middleware.php的文件,这个文件是用来配置Hyperf中间件的。

<?php

return [
    // 中间件列表,放在最前面的中间件优先执行
    'http' => [
        // 允许跨域请求的中间件
        Hyperf\HttpServer\Middleware\CorsMiddleware::class,
        // PSR-15 标准响应式中间件,会调用响应对象的 send 方法
        Hyperf\HttpServer\Middleware\PsrResponseMiddleware::class,
        // 记录请求和响应日志
        Hyperf\HttpServer\Middleware\RequestLoggerMiddleware::class,
    ],
    // WebSocket 监听
    'ws' => [
        // 默认中间件,记录 WebSocket 的请求和响应
        Hyperf\WebSocketServer\Middleware\WebSocketMiddleware::class,
    ],
];

在这个文件中,我们可以看到有一个名为http的中间件组。

我们可以通过这个中间件组来修改服务器端发送的响应头。

http中间件组中,我们可以添加如下代码:

'Hyperf\HttpServer\Middleware\ResponseMiddleware::class',

这段代码的作用是,将Hyperf\HttpServer\Middleware\ResponseMiddleware中间件添加到中间件组中。

这个中间件可以用来修改服务器端发送的响应头。

Hyperf\HttpServer\Middleware\ResponseMiddleware中间件中,我们可以添加如下代码:

// 设置下载文件的文件名
if ($response instanceof \Hyperf\HttpMessage\Stream\Response) {
    $filename = $request->header('filename', $response->filename());
    $response = $response->withHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
}

// 返回修改后的响应对象
return $response;

这段代码的作用是,如果服务器端返回的是一个文件,则将文件的名称设置为filename头中的值。

踩坑记录

在实现这个需求的过程中,我遇到了以下几个坑:

  • 坑1:content-disposition头中的文件名乱码

在修改vue-element-admin的拦截器时,我发现content-disposition头中的文件名是乱码的。

经过一番调试,我发现这是因为服务器端发送的文件名是经过编码的。

为了解决这个问题,我需要在服务器端对文件名进行解码。

  • 坑2:filename头不起作用

在修改Hyperf后端中间件时,我发现filename头不起作用。

经过一番调试,我发现这是因为服务器端没有设置filename头。

为了解决这个问题,我需要在服务器端设置filename头。

总结

通过修改vue-element-admin拦截器和Hyperf后端中间件,我们可以实现使用Header头内容作为下载的文件名。

希望这篇文章对有需要的读者有所帮助。