前言
最近的工作中与前端同事对接频繁的遇到跨域问题,好在都解决了,对此抽点时间对前后端分离开发产生的跨域问题已经解决方案做一个总结。
为什么会引起跨域?
浏览器的同源策略引起跨域问题
什么是跨域?
跨域是指跨域名的访问,
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
其实做过前后端分离开发的朋友都知道,这样一定会存在跨域问题!
跨域的解决方案
简单介绍我知道的三种跨域的解决方案
1.Jsonp
Jsonp是最早期的跨域解决方案,利用script标签的src属性发送请求。(script标签是不受同源策略的影响的)。
但是这种方式只能发起Get请求,后端也必须使用@RequestMapping(method = RequestMethod.GET)或GetMapping来处理。
2.Nginx
通过Nginx的反向代理解决跨域问题。
将前端资源部署到nginx上,通过配置代理解决跨域问题server { listen 端口号; server_name IP地址; charset utf-8; # 允许的文件类型配置 location ~ /.*\.(html|htm|js|css|png|jpg|woff|eot|svg|ttf|ico)$ { root 静态资源路径(或页面路径); index index.html } # 代理配置 location /请求前缀 { proxy_pass 代理地址; } }
前端在请求后端接口时不需要再指定后端的域名和端口,这样默认使用的就是前端的域名和端口。
访问Nginx上的页面资源,页面发起请求时Nginx会自动的帮我们代理到目标服务
3.CROS
CORS是一个W3C标准,全称是:跨域资源共享,它允许浏览器想跨源服务器发出XML HttpRequest请求,从而克服了AJAX只能同源使用的限制
CORS需要浏览器和服务器同时支持,目前所有的浏览器都支持该功能(IE浏览器不能低于IE10)
浏览器端:
目前所有的浏览器都支持(除了IE10以下不能)整个CORS通信过程,都是浏览器自动完成,不需要用户参与
服务器端:
CROS通信与AJAX没有任何差别,因此不需要改变以前的业务逻辑,只不过,浏览器会在请求头中携带一些头的信息,我们需要以此判断是否允许其跨域,然后在响应头中加入一些信息即可(这一般过滤器完成功能)
好文推荐:跨域资源共享CORS详解
在后端服务中配置跨域
1.在过滤器中配置跨域
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Author ScholarTang
* @Date 2020/7/31 5:53 下午
* @Desc 配置跨域的过滤器
*/
@Component
@WebFilter(urlPatterns = "/*",value = "crosFilter")
public class CrosFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
/** 配置跨域的代码 **/
/**
* 浏览器会自动检测请求是否跨域,如果是跨域请求的话浏览器会自动的在请求头中加入
* Origin字段,其值就是请求源信息(协议 + 域名 + 端口)
* 在此获取这个请求源,对其进行允许访问操作
*/
response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
//是否允许使用cookie
response.setHeader("Access-Control-Allow-Credentials","true");
//允许的请求头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With,X-App-Id, X-Token");
//允许的请求方式
response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
//预检请求的有效期
response.setHeader("Access-Control-Max-Age", "3600");
filterChain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
通过编写一个配置类来解决跨域问题
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;
/**
* @Author ScholarTang
* @Date 2020/7/31 6:53 下午
* @Desc 配置跨域的过滤器
*/
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*(允许所有域),否则cookie就无法使用了
// config.addAllowedOrigin("*");
config.addAllowedOrigin("http://10.43.57.173:8090");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}