element的el-upload组件上传文件跨域问题的几种解决
前言
最近在开发基于 SpringBoot
和 Vue
的前后端分离项目的时候,在使用 element-ui
的 el-upload
组件的时候遇到了跨域的问题,尽管之前我也写过一篇关于解决跨域问题的文章,但是发现还是无法解决使用 action
时的跨域问题,因此本文将基于后端 SpringBoot
和 基于 nginx
反向代理的解决跨域的方法,本文的完整代码(前端和后端代码)也已上传到GitHub。
使用 action 的解决方法
在具体的讲解之前先声明,本文的后端都基于 8888
端口,前端基于 8080
端接口,nginx
代理端口为 80
。下面是前端使用 el-upload
的代码,为了方便专注于跨域问题,已去掉不必要的属性:
<el-upload class="upload-demo" action="http://localhost/nginx/uploadByAction" :file-list="fileList"> <el-button size="small" type="primary">点击上传</el-button> </el-upload>
下面是后端的配置文件(application.yaml
)代码:
server: port: 8888 upload: filePath: D:\\Temp\\img\\
基于 nginx 反向代理的解决方法
后端接口代码如下:
@RestController public class UploadByAction { @Value("${upload.filePath}") private String filePath; @PostMapping("/nginx/uploadByAction") public String uploadByNginx(@RequestPart("file") MultipartFile file) { return getUploadMsg(file); } private String getUploadMsg(@RequestPart("file") MultipartFile file) { if (file.isEmpty()) { return "上传失败,请选择文件"; } String fileName = file.getOriginalFilename(); File dest = new File(filePath + fileName); try { file.transferTo(dest); return "上传成功"; } catch (IOException e) { e.printStackTrace(); return "上传失败"; } } }
nginx
代理配置如下:
location / { root html; add_header Access-Control-Allow-Origin *; if ($request_method = 'OPTIONS') { return 204; } proxy_pass http://localhost:8888; index index.html index.htm; }
只要以上简单的 nginx
配置便解决了使用 ation
时的跨域问题,相信看过前言里我说的解决跨域问题的那篇文章的同学会发现,这里的nginx
配置只是多了下面这句:
if ($request_method = 'OPTIONS') { return 204; }
这里是因为使用 action
时,会发送一个预检请求
,关于预检请求
的详细介绍,可以查看这篇文章,这里的配置主要是为了让预检请求
正常的返回,其实仔细查看点击了上传时的Network
,就会后台其实发送了两个请求:
基于 SpringBoot 后台代码的解决方法
其实基于 SpringBoot
后台代码的解决方法也就是将上述的 nginx
反向代理配置改成了具体的代码配置而已,下面就具体介绍,首先由于现在不再使用反向代理了,el-upload
里的 action
属性也需要改为 http://localhost:8888/springboot/uploadByAction
,然后就是后台代码的改变:
首先是 controller
接口的代码:
@RestController public class UploadByAction { @Value("${upload.filePath}") private String filePath; @PostMapping("/springboot/uploadByAction") public String uploadBySpringBoot(@RequestPart("file") MultipartFile file) { return getUploadMsg(file); } private String getUploadMsg(@RequestPart("file") MultipartFile file) { if (file.isEmpty()) { return "上传失败,请选择文件"; } String fileName = file.getOriginalFilename(); File dest = new File(filePath + fileName); try { file.transferTo(dest); return "上传成功"; } catch (IOException e) { e.printStackTrace(); return "上传失败"; } } }
然后是拦截器的设置:
@Configuration public class CorsInterceptor implements HandlerInterceptor { @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.addHeader("Access-Control-Allow-Origin", "*"); if ("OPTIONS".equals(request.getMethod())) { return true; } return HandlerInterceptor.super.preHandle(request, response, handler); } }
最后添加拦截器:
@Configuration public class ApiConfig extends WebMvcConfigurationSupport { private final CorsInterceptor corsInterceptor; @Autowired public ApiConfig(CorsInterceptor corsInterceptor) { this.corsInterceptor = corsInterceptor; } @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(corsInterceptor).addPathPatterns("/**"); super.addInterceptors(registry); } }
完成以上配置后便不再需要使用 nginx
反向代理的配置,也可以直接访问 8888
端口请求资源了。
不使用 action 的解决方法
下面再讲讲不使用 action
的解决方法,其实还是推荐不使用 action
,自己处理 ajax
请求可以更自由一些。
首先是前端的代码:
<el-upload class="upload-demo" action="" :http-request="upload"> <el-button size="small" type="primary">点击上传</el-button> </el-upload>
由于不再使用 action
,因此这里的值任意,http-request
里的值对应自己处理请求的方法,upload
方法如下(使用了 axios
发送 ajax
请求):
upload(param) { const formData = new FormData() formData.append('file', param.file) const url = 'http://localhost:8888/uploadWithoutAction' axios.post(url, formData).then(data => { console.log('上传图片成功') }).catch(response => { console.log('图片上传失败') }) }
对应的后台处理的 controller
代码如下:
@RestController public class UploadWithoutAction { @Value("${upload.filePath}") private String filePath; @PostMapping("/uploadWithoutAction") public String upload(@RequestPart("file") MultipartFile file) { if (file.isEmpty()) { return "上传失败,请选择文件"; } String fileName = file.getOriginalFilename(); File dest = new File(filePath + fileName); try { file.transferTo(dest); return "上传成功"; } catch (IOException e) { e.printStackTrace(); return "上传失败"; } } }
由于在使用 action
的解决方法里已经配置过拦截器设置了 response.addHeader("Access-Control-Allow-Origin", "*");
这里就不再需要配置跨域了,如果想通过 nginx
反向代理解决跨域,以上的拦截器都不要设置,然后把上文中 nginx
反向代理配置中的关于 OPTIONS
的处理配置去掉即可,当然不去掉也没什么影响,如果不使用 action
了,参考我前言里的处理跨域的那篇文章即可。
总结
本文简单介绍了如何处理使用 el-upload
的 action
时的跨域问题,其实本质还是解决 OPTIONS
的预检请求
请求问题。
到此这篇关于element的el-upload组件上传文件跨域问题的几种解决的文章就介绍到这了,更多相关element el-upload 上传跨域内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
详解Vue+ElementUI从零开始搭建自己的网站(一、环境搭建)
这篇文章主要介绍了Vue+ElementUI从零开始搭建自己的网站(一、环境搭建),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2019-04-04vue项目实现会议预约功能(包含某天的某个时间段和某月的某几天)
这篇文章主要介绍了vue项目实现会议预约功能(包含某天的某个时间段和某月的某几天),本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2023-02-02对vue v-if v-else-if v-else 的简单使用详解
今天小编就为大家分享一篇对vue v-if v-else-if v-else 的简单使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2018-09-09vue-router3.0版本中 router.push 不能刷新页面的问题
这篇文章主要介绍了vue-router3.0版本中 router.push 不能刷新页面的问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-05-05
最新评论