〇、遇到跨域安全问题
在学习SpringBoot过程中,遇到了这样一个问题。当时用SpringBoot开发Rest服务接口,然后用Ajax请求获取数据,来实现前后端分离。但是在前端请求时,始终不能显示应该显示的数据。从浏览器的控制台报错来看(如下图),应该是遇到了跨域安全的问题。
一、为什么会出现跨域安全问题?
要解决这个问题,首先得知道为什么会出现这个问题。通过了解,出现跨域安全问题的原因一般是以下三个问题:浏览器收到了正确的返回数据但是做出了限制、发出去的请求是XMLHttpRequest请求而不是JSON请求、前后端协议域名端口等不一样造成了跨域。
二、怎么去解决出现的跨域安全问题?
根据上面的三个问题,去解决这次出现的跨域安全问题。
1. 让浏览器不去做限制
不同的浏览器应该有不同的设置参数的方法。例如谷歌浏览器就是disable-web-security。不过我们在应用中应该不会让我们的用户去改浏览器的参数,所以我没有采用这种方法。
2. 让发出去的请求不是XMLHttpRequest请求
在网上搜了一下,不少解决方法是把请求数据类型设为JSONP。但是存在一个问题就是如果用JSONP类型请求那么后台的服务接口也要做改动,因为用JSONP数据类型的请求虽然不是XHR但也不是JSON而是Script。而我想用的是JSON来实现前后端传输数据,而且JSONP对GET方式以外的请求不支持(我想用REST啊怎么可以木有POST\PUT\DELETE),所以我也没有采用这种方法。
3. 解决前后端协议域名端口等不一样造成的跨域。
解决跨域可以从客户端考虑,也可以从服务端考虑。从客户端考虑,可以用代理来将服务端的请求转换成与客户端相同的域的请求从而解决跨域问题;从服务端考虑,可以考虑在响应头里增加字段。因为服务端就是我用SpringBoot写的,而增加字段并不需要对每个接口进行改动,只要添加一个拦截器在所有的返回里添加返回头就可以了。当然,如果是调用别人家的接口,无法改动别人的服务端,那就只能考虑在客户端这边加代理了。
根据控制台的错误信息,可以在服务端添加请求头Access-Control-Allow-Origin,来告诉浏览器服务端允许这个跨域。SpringBoot中我用的实现方式是增加一个Filter来拦截所有的请求在返回头里添加Access-Control-Allow-Origin和Access-Control-Allow-Method字段。事例代码如下(仅供参考):
/*SpringBoot启动类*/
package net.tsingmo.SpringBootDemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
@Bean
public FilterRegistrationBean filterRegistrationBean () {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setFilter(new ResponseHeaderFilter());
return filterRegistrationBean;
}
}
/*ResponseHeaderFilter类*/
package net.tsingmo.SpringBootDemo;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ResponseHeaderFilter implements javax.servlet.Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
httpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.addHeader("Access-Control-Allow-Methods", "GET");
filterChain.doFilter(servletRequest, httpServletResponse);
}
@Override
public void destroy() {}
}