window.open无法下载问题及其axios解决下载问题的方法,附hutool工具导出导入Excel的功能

在前端页面使用window.open只会自动跳转但不会自动下载的问题

项目场景:在最近一直忙着做毕设,跟着b站程序员青戈敲代码,视频里面使用window.open(url)可以正常制动下载,但是到我这里就却发现只是打开页面但不能自动下载。


问题描述

在后端使用hutool工具准备好了一个Excel导出接口

 @GetMapping("/export")
    public void exportExcel(HttpServletResponse response) throws IOException {
        // 从数据库查询出所有的数据
        List<User> list = userLogin.list();
        // 通过工具类创建writer 写出到磁盘路径
//        ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath + "/用户信息.xlsx");
        // 在内存操作,写出到浏览器
        ExcelWriter writer = ExcelUtil.getWriter(true);

        // 一次性写出list内的对象到excel,使用默认样式,强制输出标题
        writer.write(list, true);

        // 设置浏览器响应的格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息", "UTF-8");
//        在controller层中的二进制流文件下载方法下配置放行属性:
        response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);
        out.close();
        writer.close();
    }

前段vue代码

//前端模版
<template>
	<el-button type="primary" @click="handleExportExcel">导出 <i class="el-icon-top"></i></el-button>
</template>

//js控制逻辑
 handleExportExcel() {
 			window.open(url)
             this.load();
         }

原因分析:

结果页面不能自动跳转,查了一下原因是因为协议的问题,把http改成https就成功了,Chrome这些浏览器不允许不安全的下载行行为自动下载,htttp协议是不安全的。但是我们开发一般都用http做测试,这个问题的解决办法可以采用如下方法。原文在这

解决方案:

// 以之前的post请求举例
axios.post(url, {...someparams}, {responseType: 'blob'})
    .then((res) => {
        const { data, headers } = res
        //要在后端响应体自行设置content-disposition属性,否则可能无法获取到文件名,导致无法下载。(ps嫌麻烦直接删除这个步骤)
        const fileName = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1')
        // 此处当返回json文件时需要先对data进行JSON.stringify处理,其他类型文件不用做处理
        //const blob = new Blob([JSON.stringify(data)], ...)
        const blob = new Blob([data], {type: headers['content-type']})
        let dom = document.createElement('a')
        let url = window.URL.createObjectURL(blob)
        dom.href = url
        dom.download = decodeURI(fileName)
        dom.style.display = 'none'
        document.body.appendChild(dom)
        dom.click()
        dom.parentNode.removeChild(dom)
        window.URL.revokeObjectURL(url)
    }).catch((err) => {})


本质借助生成虚拟dom的方法,通过调用a标签上的属性触发事件,完成下载。

附:hutool工具下如何导入导出文件

导入pom依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.20</version>
</dependency>
 <dependency>
     <groupId>org.apache.poi</groupId>
     <artifactId>poi-ooxml</artifactId>
     <version>4.1.2</version>
 </dependency>

编写实体类

//开启了swagger配置
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("sh_user")
@ToString
public class User {
    @Alias("用户ID")//一定要设置导出导入的别名,否则会将数据库中的英文列名导出
    @ApiModelProperty("用户ID")
    @TableId(type=IdType.AUTO)
    private Integer id;

    @ApiModelProperty("账户号码")
    @Alias("账户号码")
    private String accountNumber;

    @JsonIgnore
    @Alias("用户密码")
    private String userPassword;

    @ApiModelProperty("用户头像路径")
    @Alias("用户头像路径")
    private String avatar;

    @ApiModelProperty("用户状态")
    @Alias("用户状态")
    private Integer userStatus;

    @ApiModelProperty("昵称")
    @Alias("昵称")
    private String nickname;

    @Alias("注册时间")
    @ApiModelProperty("注册时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date signInTime;
}

编写mapper和service时,由于业务逻辑不负责,直接在controller中写逻辑

//导入代码
@PostMapping("/import")
    public void importExcel(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<User> list = reader.readAll(User.class);
        userLogin.saveBatch(list);
    }
    //导出代码上面已经有,所以不在重复

前端页面

<el-upload
       style="display: inline-block;padding:5px"
        class="upload-demo"
        :show-file-list="false"
        action="http://localhost:8081/user/import" accept="xlsx"
        :on-success="handleExcelImportSuccess"
        :on-error="handleExcelImportError">
    <el-button  type="primary">点击上传<i class="el-icon-bottom"></i></el-button>
</el-upload>

//js
//处理导入成功和失败对应的事件
 handleExcelImportSuccess(){
      this.$message.success("导入成功")
           this.load()
       },
 handleExcelImportError(){
           this.$message.success("导入失败!文件不合格");
       }

总结

至此代码业务逻辑完毕,算做一个小小的学习经验吧!
### 回答1: vue.js 是一个开源的 JavaScript 框架,用于构建用户界面,而 axios 是一个基于 promise 的 HTTP 客户端,用于在浏览器和 Node.js 中发送 HTTP 请求。 在 vue.js 中使用 axios 进行跨域访问时,可能会出现跨域访问错误。跨域是指在浏览器中通过 JavaScript 发起一个 HTTP 请求,该请求的目标服务器是与当前页面不同域名、端口或协议的地址。 解决这个问题方法有多种: 1. 后端配置允许跨域访问:在后端服务器中进行配置,允许指定的域名或端口进行跨域访问。 2. 使用代理进行跨域请求:在 vue.config.js 文件中配置代理,将跨域请求转发到目标服务器。例如,在 vue.config.js 文件中添加以下配置: ```javascript module.exports = { devServer: { proxy: { '/api': { target: 'http://api.example.com', changeOrigin: true, pathRewrite: { '^/api': '' } } } } }; ``` 这样,当你在前端代码中发送以“/api”开头的请求时,将会使用代理进行跨域请求。 3. JSONP:如果目标服务器支持 JSONP,可以使用 JSONP 进行跨域请求。在 axios 中,默认是不支持 JSONP 的,但可以通过配置实现。例如,在请求中添加“jsonp”参数: ```javascript axios.get('http://api.example.com/data', { params: { callback: 'jsonCallback', dataType: 'jsonp' } }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); }); ``` 通过以上方法,可以解决 vue.jsaxios 跨域访问错误问题。根据具体情况选择合适的解决方法,以确保跨域请求能够正常进行。 ### 回答2: Vue.js中使用axios请求数据时,常常会遇到跨域访问错误。这是因为浏览器的同源策略限制了不同域名之间的访问。 解决这个问题方法有几种: 1. 使用代理 可以在项目的配置文件(vue.config.js或者nuxt.config.js)中配置代理。通过将请求代理到同域名下的接口,实现跨域访问。 例如,可以在配置文件中添加如下代码: ```javascript module.exports = { devServer: { proxy: { '/api': { target: 'http://api.example.com', changeOrigin: true, pathRewrite: { '^/api': '' } } } } } ``` 然后,在axios的请求中使用相对路径(不包含域名)进行访问。例如: ```javascript axios.get('/api/data') .then(response => { console.log(response.data) }) ``` 这样就可以跨域访问目标接口了。 2. 设置服务器响应头 在目标服务器上,设置允许跨域访问的响应头。一般来说,可以在后端的接口代码中添加以下响应头: ```javascript app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); next(); }); ``` 这样浏览器就会允许跨域访问该接口了。 3. JSONP JSONP是一种前端跨域访问的解决方案。通过在请求中添加一个回调函数作为参数,服务器将返回该函数的调用,并将数据作为参数传递给该函数。 例如,在axios请求中使用JSONP: ```javascript axios.jsonp('http://api.example.com/data?callback=handleData') .then(response => { console.log(response.data) }) ``` 然后,在全局定义一个处理返回数据的函数: ```javascript function handleData(data) { console.log(data) } ``` 这样就可以通过JSONP实现跨域访问了。 以上是几种解决Vue.jsaxios跨域访问错误的方法,可以根据具体情况选择使用。 ### 回答3: 在Vue.js中,由于浏览器的同源策略,如果我们的Vue应用与后端接口的域名或端口不一致,会出现跨域访问错误。然而,我们可以使用axios库来解决这个问题。 首先,为了解决跨域访问错误,我们可以在后端的API接口中添加响应头Access-Control-Allow-Origin: *,允许所有来源的请求访问接口。当然,我们也可以根据需求设置特定的源或域名。 另外,我们还可以通过设置代理来解决跨域访问问题。在项目的根目录下的`vue.config.js`文件中,我们可以使用`devServer`配置项来设置代理。例如,我们可以将/api路径下的请求代理到http://localhost:8000路径下,具体配置如下: ``` module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8000', changeOrigin: true, pathRewrite: { '^/api': '' } } } } } ``` 以上配置意味着,当我们的Vue应用发起/api路径下的请求时,它将被代理到http://localhost:8000路径下。`changeOrigin`选项设置为true时,请求头中的host会被设置为目标url,同时`pathRewrite`选项可以重写请求路径,删除/api前缀。 在前端代码中,我们可以使用axios来发起跨域请求。例如,我们可以在Vue的组件中使用axios来请求后端接口: ``` import axios from 'axios' export default { methods: { fetchData() { axios.get('/api/data') .then(response => { // 处理响应数据 }) .catch(error => { // 处理错误 }) } } } ``` 通过以上方法,我们可以解决Vue.jsaxios跨域访问错误问题,实现与后端接口的跨域通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值