什么是跨域?
瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、端口、協議任一不同,都是跨域
原因:
由於瀏覽器的同源策略, 即a網站只能訪問a網站的內容,不能訪問b網站的內容.
注意:
跨域問題只存在於瀏覽器,也就是說當你的前端頁面訪問后端簡單請求的接口時,返回值是有的,只是服務器沒有在請求頭指定跨域的信息,所以瀏覽器自動把返回值給"屏蔽了".
經過上面的了解,可以得出幾個解決跨域的方法(不考慮前端實現):
1.服務端指定跨域信息
2.在web頁面與服務器之間加一層服務指定跨域信息,比如nginx
使用springboot提供了跨域的方法:
1.5版本為繼承WebMvcConfigurerAdapter 類實現抽象方法,
//springboot 1.5方式 @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedHeaders("*") .allowedMethods("*") .allowedOrigins("*") .allowCredentials(true); } }
2.0以后為實現WebMvcConfigurer 接口重寫方法
//springboot 2.0以上的方式 @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token") .allowedMethods("*") .allowedOrigins("*") .allowCredentials(true); } }
使用攔截器實現跨域:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.addHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,token"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }); } }
注意:
請求頭中自定義的字段是不允許跨域的,所以要指定
response.addHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,token");
或者
response.addHeader("Access-Control-Allow-Headers", "*");
還可以使用servlet提供的過濾器進行跨域配置:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * 請求的基本過濾器 預處理請求頭 */ @Component @WebFilter(urlPatterns = {"/*"}, filterName = "tokenAuthorFilter") public class TokenAuthorFilter implements Filter { private static Logger LOG = LoggerFactory.getLogger(TokenAuthorFilter.class); @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse rep = (HttpServletResponse) response; HttpSession session = req.getSession(); LOG.info("sessionId:{}", session.getId()); //LOG.info("Origin:{}", req.getHeader("Origin")); //設置允許跨域的配置 // 這里填寫你允許進行跨域的主機ip(正式上線時可以動態配置具體允許的域名和IP) rep.setHeader("Access-Control-Allow-Origin", "*"); //rep.setHeader("Access-Control-Allow-Origin", "*"); rep.setHeader("Access-Control-Expose-Headers", jwtProperties.getHeader()); // 允許的訪問方法 rep.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); // Access-Control-Max-Age 用於 CORS 相關配置的緩存 rep.setHeader("Access-Control-Max-Age", "3600"); rep.setHeader("Access-Control-Allow-Headers", "token, Origin, X-Requested-With, Content-Type, Accept"); //若要返回cookie、攜帶seesion等信息則將此項設置我true rep.setHeader("Access-Control-Allow-Credentials", "true"); // 把獲取的Session返回個前端Cookie //rep.addCookie(new Cookie("JSSESIONID", session.getId())); chain.doFilter(req, rep); } @Override public void init(FilterConfig arg0) throws ServletException { } }
靈活的跨域方式:
如果我們只想提供一個方法可以跨域,那么可以使用注解的形式:
@CrossOrigin @RestController public class TestController { }