实际工作中遇到了,在此做个笔记,希望能够帮助到遇到此问题的猿友们!!!
目录
问题场景
编辑此时作者后端代码为:
自定义过滤器:
WebMvcConfig配置文件: 注入自定义过滤器
解决方法
1.后端代码中设置解决跨域代码
2.使用Nginx进行解决跨域
3.设置Access-Control-Allow-Origin允许多域名访问
方式一:设置允许多域名访问最简单的方法是使用通配符。
方式二:使用数组过滤的方式
问题场景
前端访问后端接口从页面控制台Network中看到接口报错,请求方法为OPTIONS,状态值为302;
页面控制台中报错:No 'Access-Control-Allow-Origin' header is present on the requested resource
此时作者后端代码为:
自定义过滤器:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyFilterConfig implements Filter {
private Logger logger= LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
//*表示允许所有域名跨域
httpResponse.setHeader("Access-Control-Allow-Origin","*");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
httpResponse.setHeader("Access-Control-Max-Age", "5000");
httpResponse.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,Authorization,Token");
filterChain.doFilter(servletRequest, servletResponse);
}
}
WebMvcConfig配置文件: 注入自定义过滤器
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Value("${file.fileMapPath}")
private String fileMapPath;
/**
* 自定义过滤器,解决前后端分离跨域问题
* @return
*/
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
//传入自己创建的filter
filterRegistrationBean.setFilter(new MyFilterConfig());
//设置拦截路径
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
解决方法
1.后端代码中设置解决跨域代码
方式一:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyFilterConfig implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
//*表示允许所有域名跨域
logger.info("进入过滤器");
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "5000");
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, Authorization, Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
String method = request.getMethod();
if (method.equalsIgnoreCase("OPTIONS")) {
servletResponse.getOutputStream().write("Success".getBytes("utf-8"));
} else {
filterChain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
方式二:response.setHeader("Access-Control-Allow-Origin", "*");
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyFilterConfig implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
//*表示允许所有域名跨域
logger.info("进入过滤器");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "5000");
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, Authorization, Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
String method = request.getMethod();
if (method.equalsIgnoreCase("OPTIONS")) {
servletResponse.getOutputStream().write("Success".getBytes("utf-8"));
} else {
filterChain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
2.使用Nginx进行解决跨域
例:前端工程部署时使用浏览器默认端口:80 。后端工程端口为 8080 。nginx 监听端口 8082 。
前端请求后端 URL 为:http:// nginx所在服务器 IP : 8082 。
前端工程请求 8082,nginx 收到请求再转发到实际服务,取得数据,并最终再返回。
(nginx 所在服务器也就是代理服务器,可以和后端服务器为同一主机)
在 nginx 配置文件中设置为:
端口占用情况如下:红框是 nginx 、黄框是前端工程、蓝框是后端工程。
3.设置Access-Control-Allow-Origin允许多域名访问
方式一:设置允许多域名访问最简单的方法是使用通配符。
注:这种方式允许所有域名都可以访问,并不安全,而且这种方式浏览器不能携带cookie信息(携带cookie信息只能使用真实域名,如下面第二中方式)。这种方式只推荐在不带cookie信息的开发中测试使用。
response.setHeader("Access-Control-Allow-Origin", "*");
方式二:使用数组过滤的方式
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class MyFilterConfig implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.info("过滤器初始化");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
//*表示允许所有域名跨域
logger.info("进入过滤器");
// 设置允许多个域名请求
String[] allowDomains = {"http://www.toheart.xin","http://192.168.11.213:8080","http://localhost:8080"};
Set allowOrigins = new HashSet(Arrays.asList(allowDomains));
String origin = request.getHeader("Origin");
if(allowOrigins.contains(origin)){
//设置允许跨域的配置
// 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
response.setHeader("Access-Control-Allow-Origin", origin);
}
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "5000");
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, Authorization, Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
String method = request.getMethod();
if (method.equalsIgnoreCase("OPTIONS")) {
servletResponse.getOutputStream().write("Success".getBytes("utf-8"));
} else {
filterChain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
期待大家的三连击,你们的支持是我的动力。加油,猿友们!!
转载请注明:解决前后端跨域问题No‘Access-Control-Allow-Origin‘... | 胖虎的工具箱-编程导航