【后端】请求携带未知请求头导致跨域问题(后端配置跨域无效)

最近工作开发我写了一个文件上传的接口,接收MultipartFile。以下文件上传代码加最后补充 过滤器 代码 可以直接使用。如下代码:

//伪代码

@RestController
//跨域注解
@CrossOrigin
@RequestMapping("/test")
public class TestController {
	
	@RequestMapping("/queryData")
    public void queryData(){
        System.out.println("查询方法生效");
    }

    @RequestMapping("/upload")
    public void upload(@RequestPart("filesData")MultipartFile multipartFile){
        System.out.println("文件上传方法生效");
    }
}

拦截器与配置代码如下:

//拦截器类
public class WebInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    	//TODO:判断token逻辑自行处理
        String token = request.getHeader("token");
        if (token == null) {
            return false;
        }
        return true;
    }
}

//配置接口路径使用拦截器类
@Configurable
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new WebInterceptor())
                .addPathPatterns("/**");
    }
}

前端代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
	<input type="file" id="fileInput" multiple accept=".jpg,.jpeg,.png" /> 
	<button type="button" onclick="uploadFiles()">上传文件</button> 
	<button type="button" onclick="queryData()">测试查询</button> 
	
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
	function queryData(){
		let config = {
		    headers: {'token':'123'}
		}
		axios.post('http://localhost:8081/test/queryData',{},config).then(res => {
			console.log('查询数据成功:', res);
		})	
	}
	function uploadFiles() {
	    const fileInput = document.getElementById('fileInput');
		const files = fileInput.files;
		// 创建 FormData 对象
		const formData = new FormData();
		// 将每个文件添加到 FormData 对象中
		for (let i = 0; i < files.length; i++) {
		    formData.append('filesData', files[i]);
		}
		let config = {
		    headers: 
		    {
				'Content-Type': 'multipart/form-data;charset=utf-8',
				'token':'123'
			}
		 }
		axios.post('http://localhost:8081/test/upload',formData,config)	
		.then(response => {
		    alert('上传成功');
		})
		.catch(error => {
		    alert('上传失败,请重试');
		});
	}
</script>
</html>

前端在Hbuilder中运行的。本地且有自己的端口(模拟前后端分离跨域问题)
在这里插入图片描述

流程: 通过axios使用 multipart/form-data 方式请求上传接口。后端实现一个拦截器(HandlerInterceptor) 对请求中请求头的token进行验证是否正确。正确就可以通过拦截器进行请求。后端接口接收到文件二进制数据。然后就上传文件时出现了问题。

跨域讲解(简单易懂)

1.发现问题

在这里插入图片描述
前端8848端口请求后端upload接口导致跨域问题。

2.解决问题

因为工作中出现的问题,我为了快速解决,然后去做其它的事情想到了注解 @CrossOrigin 去快速解决跨域。在前面贴的代码中我也加上了。并且在这个复现过程中我也加上了。我就奇怪了。还是报错跨域问题。第一反应就是 “难不成这个注解因为可以快速解决问题所以设计的不完善又或者是因为使用快速开发框架的原因里面有某些配置有隐藏bug给拦住了?”。然后就想到了用全局配置类解决。于是乎我又配置了一个百度上随便摘抄了一个 跨域配置类;

//跨域注解配置类
@Configuration
public class GlobalCorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        //1. 添加 CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        // 放行哪些原始域
        config.addAllowedOriginPattern("*");
        // 是否发送 Cookie
        config.setAllowCredentials(true);
        // 放行哪些请求方式
        config.addAllowedMethod("*");
        // 放行哪些原始请求头部信息
        config.addAllowedHeader("*");
        // 暴露哪些头部信息
        config.addExposedHeader("*");
        //2. 添加映射路径
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",config);
        //3. 返回新的CorsFilter
        return new CorsFilter(corsConfigurationSource);
    }
}

Copy一段上述代码后我重新开始了测试。不仅上传文件导致跨域问题未解决后台还出现了新报错:

When allowCredentials is true, allowedOrigins cannot contain the special value “*” since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider using “allowedOriginPatterns” instead.

在这里插入图片描述

于是乎我以为是这个报错导致的跨域没生效,紧接着我又去查找这个问题产生的原因:
解决上述问题博客

弄好后重新测试,发现正常了。于是我把跨域配置类放到自己的项目中。在自己项目环境中测试一下文件上传。依旧出现了跨域问题。
在这里插入图片描述
到这里已经百思不得其解了。找了Axios问题,找了Spring问题,找了前端问题。搜了很久。最后搜到了答案。

链接中回答有一句话是这么说的:

后端不允许user-token这个报头,因此OPTIONS预检发现目标到达不了,跟axios没啥关系。

请求中预检请求未放开请求头

根据这个答案让跨域允许接收这个请求头;实际我项目中设置的是 “*” 号,也就是放开所有。可是最后还是出现了跨域问题。我这里应该是有上述的问题,但是快速开发框架估计底层还是有一些拦截之类的?。同样出现了跨域问题。

3.过滤器解决跨域

最后我在Spring中实现了一个过滤器,因为这个过滤器实现跨域代码看着多加上偏向于更底层,我就一直不咋用这个配置,都是用的跨域配置类解决。在里面放开token才允许访问。除了这里已经放开的token以及浏览器请求默认允许的一些请求头允许。其它自定义的都需要放开才允许访问,不然哪天就会因为找这个问题开始头疼了。

//过滤器方式解决跨域
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        // 允许所有来源进行跨域请求
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 允许发送 cookie
        response.setHeader("Access-Control-Allow-Credentials", "true");
        // 允许的请求方法
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        // 允许的请求头字段,在这里允许token请求解决
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, token");
        // 预检请求的有效期,单位为秒
        response.setHeader("Access-Control-Max-Age", "3600");
        chain.doFilter(req, res);
    }
}

以至于现在我都没明白为啥我的项目里写了跨域配置类就是不行,怎么样写都不行。像过滤器类代码中一样编写的跨域配置类,不使用 “*” 号还是一样不行。有知道的小伙伴可以在评论区为我解答一下~

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗头程序员|

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值