最近项目中引入了SpringBoot,目的是做到前后端分离开发。但实际过程中出现了很多问题,其中比较令人头疼的就是跨域问题。
场景再现
创建SpringBoot项目,引入Web、JPA和MySQL
后台接口代码如下:
@RequestMapping(value = "/l", method = RequestMethod.POST)
@ResponseBody
public List<String> add(List<String> list) {
return list;
}
前台请求代码如下:
<script type="text/javascript">
var list = [];
list.push("我");
list.push("是");
list.push("大");
list.push("帅");
list.push("逼");
postList(list);
function postList(list) {
$.ajax({
type: "post",
url: "http://localhost:8080/main/l",
data: list,
success: function (list) {
console.log(list);
},
error: function (msg) {
console.log(msg);
}
});
}
</script>
前台报错如下:
POST http://localhost:8080/main/l 500 ()
后台报错如下:
org.springframework.beans.BeanInstantiationException: Failed to instantiate [java.util.List]: Specified class is an interface
这里出现的错误原因是因为在接收数组时后台必须使用@RequestBody注解
后台代码调整如下:
@RequestMapping(value = "/l", method = RequestMethod.POST)
@ResponseBody
public List<String> add(@RequestBody List<String> list) {
return list;
}
再次请求
前台报错如下:
POST http://localhost:8080/main/l 415 ()
状态码415,数据类型有问题。
查看POST的数据
可以看到FormData的数据全部是undefined
前台代码调整如下:
<script type="text/javascript">
var list = [];
list.push("我");
list.push("是");
list.push("大");
list.push("帅");
list.push("逼");
postList(list);
function postList(list) {
$.ajax({
type: "post",
url: "http://localhost:8080/main/l",
data: JSON.stringify(list),
success: function (list) {
console.log(list);
},
error: function (msg) {
console.log(msg);
}
});
}
</script>
再次请求
前台报错如下:
POST http://localhost:8080/main/l 415 ()
再次查看POST数据,发现数据已经正常了
到这里其实我是懵逼的,因为我找了整整一个上午的资料,完全不知道事出何因。
最后我想到了contentType
于是再次调整前台代码如下:
<script type="text/javascript">
var list = [];
list.push("我");
list.push("是");
list.push("大");
list.push("帅");
list.push("逼");
postList(list);
function postList(list) {
$.ajax({
type: "post",
url: "http://localhost:8080/main/l",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify(list),
success: function (list) {
console.log(list);
},
error: function (msg) {
console.log(msg);
}
});
}
</script>
再次请求
前台报错如下:
OPTIONS http://localhost:8080/main/l net::ERR_ABORTED
查看POST数据
发现请求方法变成了Request Method:OPTIONS
然后我又查了好久,发现是跨域的问题,于是在后台添加跨域配置如下:
package com.semi.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1
corsConfiguration.addAllowedHeader("*"); // 2
corsConfiguration.addAllowedMethod("*"); // 3
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
再次请求
终于成功了。真是内牛满面
总结
使用Ajax请求SpringBoot开发的后台接口时一定要注意:
前台:
1、一定要添加
contentType: "application/json;charset=UTF-8"
2、对于数组,一定要使用
JSON.stringify(list)
进行字符串格式化
后台:
1、一定要在List<E>数据类型前面添加@RequestBody注解
2、一定要进行跨域访问配置
最后
还有一点是关于csrf的,如果遇到此问题只需要添加如下配置类关闭该功能即可。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
喜欢的请关注哦!