跨域的产生以及为什么会跨域
一、为什么会跨域
跨域的根本原因是因为浏览器的一个安全策略,既同源策略,就是说一个浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
二、什么样的请求才是跨域?
请求的路径需要和当前页面不在同一域名也不在同一ip和端口
之内的请求为跨域请求
三、跨域如何解决
1、设置响应允许跨域
1.1、单独的controller
@RestController
@RequestMapping("/api/test")
public class TestController {
@ResponseBody
@RequestMapping("/getTest")
public Map<String,Object> getPhysiotherapyTypeList(HttpServletResponse response) {
Map<String,Object> map = new HashMap<>();
response.setHeader("Access-Control-Allow-Origin","*");
map.put("200","成功");
return map;
}
}
1.2、Spring Boot 解决
1.2.1、配置CorsFilter 和 CorsConfiguration
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
corsConfiguration.addAllowedHeader("*"); // 2允许任何头
corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等)
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}
}
1.2.2、使用Filter方式
@Component
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
2、使用jsonp解决 (只能发送get请求)
<script type="text/javascript">
$(document).ready(function() {
$.ajax({
type: "post",// (虽然类型是 post 但是发出的还是get)
url: "",
dataType: "jsonp",
jsonp: "jsonpCallback",
jsonpCallback: "callback",
success: function(data) {
console.log(data)
},
error: function(err) {
console.log(err)
}
});
})
</script>
后端
@RequestMapping("/getTest")
public void getPhysiotherapyTypeList(HttpServletResponse response,String jsonCallback) throws IOException {
JSONObject res = new JSONObject();
res.put("code","200");
PrintWriter writer = response.getWriter();
writer.println(jsonCallback + "(" + res.toJSONString() +")");
writer.close();
}
3、使用nginx配置转发
server {
listen 80;
server_name xxx.xxx.com;
location / {
root html;
index index.html index.htm;
}
location /test1{
proxy_pass http://localhost:8080/test;
}
location /test2{
proxy_pass http://localhost:8081/test;
}
}
关于nginx 后面的斜杠 请点击这里查看
4、使用后端发送http请求解决(我这里是 为了访问外部的接口)
我这里使用的是 restTemplate
public class RestTemplateMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public RestTemplateMappingJackson2HttpMessageConverter(){
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
mediaTypes.add(MediaType.TEXT_HTML);
setSupportedMediaTypes(mediaTypes);
}
}
在这里添加了一个 新的消息转换器 因为restTemplate 默认是不支持 text/plain类型的
@Configuration
public class RestTemplateConfig {
// 启动的时候要注意,由于我们在controller中注入了RestTemplate,所以启动的时候需要实例化该类的一个实例
@Autowired
private RestTemplateBuilder builder;
// 使用RestTemplateBuilder来实例化RestTemplate对象,spring默认已经注入了RestTemplateBuilder实例
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = builder.build();
// 添加一个新的 消息转换器
restTemplate.getMessageConverters().add(new RestTemplateMappingJackson2HttpMessageConverter());
return restTemplate;
}
}
之后在service 或 controller 中直接注入就可以使用了
@RestController
@RequestMapping("test")
public class ExternalCarController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/data")
public R getCarData(@PathVariable String url) {
Map map = restTemplate.getForObject("", Map.class);
return R.ok().put("list", map);
}
}