java跨域问题解决
问题描述:在使用前后端分离的情况下,前端访问后端时会出现跨域问题
解决方式:
1.设置跨域
1)、单个控制器方法CORS注解
在单个方法中加入注解@CrossOrigin。
2)、整个控制器启用CORS注解
在整个控制器上添加注解@CrossOrigin,其中origins为跨域的Url链接,maxAge为允许跨域的时间。
3)、全局CORS配置(在ResourcesConfig重写addCorsMappings方法)
2.获得跨域参数
原因:跨域时实际上发送了两次请求,第一次为OPTIONS请求,第二次才是实际的GET/POST请求
- 在OPTIONS请求中,不会携带请求头的参数,所以在拦截器上获取的请求头为空,自定义拦截器拦截成功
- 第一次求情不能通过,就无法获得第二次的请求了(例如get/post等)
- 只有第二次的请求带参数
解决:
1.处理第一次的请求
在拦截器中,如果请求为OPTION,则直接忽略:
1 String method = request.getMethod(); 2 //判断是否是OPTIONS请求,如果是则忽略 3 if(HttpMethod.OPTIONS.toString().equals(method)){ 4 return true; 5 }
2.获取参数
1).addInterceptors拦截
WebMvcConfigurer中有addInterceptors拦截方法
@Configuration public class WebMvcConfig implements WebMvcConfigurer{ @Resource private VersionInterceptor versionInterceptor; @Resource private DeviceInterceptor deviceInterceptor; //自定义拦截器 @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(versionInterceptor).addPathPatterns("/**"); registry.addInterceptor(deviceInterceptor).addPathPatterns("/**"); } }
实现DeviceInterceptor方法,获取参数
@Component public class DeviceInterceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){ //跳过请求为OPTION的请求 String method = request.getMethod(); //判断是否是OPTIONS请求 if(HttpMethod.OPTIONS.toString().equals(method)){ return true; } //以参数device为例 String device = ServletUtil.getHeader(request, HeadConstant.DEVICE, CharsetUtil.UTF_8); if(StringUilts.isEmpty(device)){ response.setContentType("application/json; charset=utf-8"); response.getWriter().print(JSONUtil.toJsonStr("请求参数不正确")); return false; } return true; } }
2)多滤器例子
//filterName:过滤器名字, urlPatterns:拦截的url,/*是都拦截 @WebFilter(filterName = "tokenFilter", urlPatterns = {"/*"}) //注入容器,没有这个注解,过滤器无效 @Component public class TokenFilter implements Filter { /** * 用于测试 */ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss SSS"); @Override public void init(FilterConfig config) throws ServletException { log.info("过滤器TokenFilter初始化"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 响应标头指定 指定可以访问资源的URI路径 String origin = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); // 设置 受支持请求标头(自定义 可以访问的请求头 例如:Token) response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,token,Origin,Content-Type,Accept"); // 指示的请求的响应是否可以暴露于该页面。当true值返回时它可以被暴露 response.setHeader("Access-Control-Allow-Credentials", "true"); /** * 发送两次请求 * 第一次是 request.getMethod()=OPTIONS * 第二次 request.getMethod()=GET/POST。。。 * 如果是OPTIONS请求则放行 */ if (HttpMethod.OPTIONS.toString().equals(request.getMethod())){ chain.doFilter(servletRequest, servletResponse); } System.out.println("-----------------------------------------------"); System.out.println("到达过滤器,时间:" + simpleDateFormat.format(new Date())); System.out.println("请求头中的Authorization:" + request.getHeader("Authorization")); System.out.println("请求URL:" + request.getRequestURL()); System.out.println("请求方式:" + request.getMethod()); chain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { log.info("过滤器TokenFilter销毁"); } }