1. 简介
随着现在前后端分离项目愈发普及,面临第一步的问题即为跨域。一般的URL地址(例如:https://www.cnblogs.com/cao-lei/)由协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址
组成,当协议、域名(子域名 + 主域名)、端口号这三项中有一项不同,则认为为不同的域,不同的域互相请求资源,即为跨域。
为了解决这一问题,需要引入CORS(Cross-origin resource sharing)跨域资源共享。它允许浏览器向跨域服务器发送请求,当浏览器发现此次请求时跨域时会在请求头添加一些附加信息,但这些改变对于用户是无感知的。
当发送CORS请求时,会先发送一次OPTIONS预请求,服务端接收到预请求时会检测本次请求是否在许可名单中,若允许才会发送正式请求,否则报错。
2. 响应头解释
响应头 | 解释 |
---|---|
Access-Control-Allow-Origin | 允许的域名。为空则不允许任何域名,为*则允许任何域名,也可指定具体域名,例如:http://www.C3Stones.com。 |
Access-Control-Allow-Methods | 允许的方法类型。为空则不允许任何类型,为*则允许任何类型,也可指定类型,例如:GET, POST, PUT, DELETE, OPTIONS, HEAD。 |
Access-Control-Allow-Headers | 允许的标头。为空则不允许任何标头,为*则允许任何标头,也可指定标头,例如:Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With。 |
Access-Control-Allow-Credentials | 是否允许接收跨域的Cookie凭证数据。默认为false,当PUT请求或者DELETE请求或者Content-Type为application/json时,设置为true。一般为了方便,设置为true。 |
Access-Control-Max-Age | 预检请求的有效期,单位为秒。在有效期内不用再发预检请求。 |
3. 添加CORS配置类解决
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Cors配置类
*
* @author CL
*
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* 配置跨域请求处理
*
* @param registry Cors注册类
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With")
.allowCredentials(true)
.maxAge(3600);
}
}
4. 配置CORS过滤器解决
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
/**
* Cors过滤器
*
* @author CL
*
*/
@Configuration
@WebFilter(filterName = "CorsFilter")
public class CorsFilter implements Filter {
/**
* 过滤
*/
@Override
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", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
chain.doFilter(req, res);
}
}
5. 注解CrossOrigin解决
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Cors示例Controller
*
* @author Administrator
*
*/
@CrossOrigin(origins = "http://www.C3Stones.com")
@Controller
@RequestMapping(value = "/cors/demo")
public class CorsDemoController {
/**
* 示例方法
*
* @return
*/
@CrossOrigin(origins = "http://www.C3Stones.com",
methods = { RequestMethod.OPTIONS, RequestMethod.GET },
maxAge = 3600)
@RequestMapping(value = "hello")
@ResponseBody
public String hello() {
return "Hello World!";
}
}