目前互联网市场流行,前端后端分离开发模式:前端(表现层)--中间层(Http请求接口+Json数据交互)--后端(业务逻辑层)
但是这种模式会引出一种新的问题:前后端交互跨域请求问题
究竟是什么事跨域,请看下面讲解:
JavaScript处于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。
简单来说就是因为JavaScript同源策略的限制,比如a.com域名下的js无法操作b.com或者a.b.com域名下的对象,更简单来说就是:不同域名下的url请求不允许通信。
解决方案如下:
1、普通web工程
1.1 引入对应jar包
com.thetransactioncompany cors-filter 1.7 com.thetransactioncompany java-property-utils 1.9
1.2 web.xml配置
CORS com.thetransactioncompany.cors.CORSFilter cors.allowOrigin * cors.supportedMethods GET, POST, HEAD, PUT, DELETE cors.supportedHeaders Accept, Origin, X-Requested-With, Content-Type, Last-Modified cors.exposedHeaders Set-Cookie cors.supportsCredentials true CORS /*
2、Spring Cloud微服务架构跨域问题解决
2.1 引入对应jar依赖
com.thetransactioncompany cors-filter 1.7 com.thetransactioncompany java-property-utils 1.9
2.2 添加接口请求CorsFilter过滤
package com.sinosoft.config;import org.slf4j.Logger;import org.slf4j.LoggerFactory;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;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configurationpublic class WebMvcConfigurer extends WebMvcConfigurerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(WebMvcConfigurer.class); /** * 添加拦截器 目的是拦截前端过来的请求 * * @param registry */ public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestLog()).addPathPatterns("/imove/**"); super.addInterceptors(registry); } /** * 解决前端跨域请求 ** 简单跨域就是GET,HEAD和POST请求,但是POST请求的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain *
* 反之,就是非简单跨域,此跨域有一个预检机制,说直白点,就是会发两次请求,一次OPTIONS请求,一次真正的请求 * * @return */ @Bean public CorsFilter corsFilter() { LOGGER.info("开启CorsFilter,解决前后端分离模式接口交互跨域问题"); final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); final CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true);// 允许cookies跨域 corsConfiguration.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin corsConfiguration.addAllowedHeader("*");// #允许访问的头信息,*表示全部 corsConfiguration.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 corsConfiguration.addAllowedMethod("*");//允许所有的请求方式 urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); return new CorsFilter(urlBasedCorsConfigurationSource); }}
3、SpringCloud 定义AOP切面来监控接口请求
package com.sinosoft.config;import com.sinosoft.domain.Deviceinfo;import com.sinosoft.dto.DeviceinfoDTO;import com.sinosoft.dto.common.IMReqeustEntity;import com.sinosoft.dto.common.RequestInfo;import com.sinosoft.repository.DeviceinfoRepository;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;/** * Created by zh on 03/29/17. */@Aspect //定义一个切面@Configurationpublic class LogRecordAspect { /** * 日志打印 */ private static final Logger LOGGER = LoggerFactory.getLogger(LogRecordAspect.class); @Autowired private DeviceinfoRepository deviceinfoRepository; /** * 定义切点Pointcut * 监控请求对应controller过来接口 */ @Pointcut("execution(* com.sinosoft.controller.*Controller.*(..))") public void excudeService() { } @Around("excudeService()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { LOGGER.info("监控前端请求management应用模块过来的接口..."); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String url = request.getRequestURL().toString();//获取接口请求详细路径 String method = request.getMethod(); //获取接口请求方法 String uri = request.getRequestURI(); //获取接口请求路径 String queryString = request.getQueryString(); //获取接口请求参数 Object[] args = pjp.getArgs(); System.out.println("请求参数:" + args[0].toString()); try { for (int i = 0; i < args.length; i++) { if (args[i] instanceof RequestInfo ) { RequestInfo r = (RequestInfo ) args[i]; //开始进行入参解密处理 //开始进行设备信息保存 IMReqeustEntity entity = r.getImReqeustEntity(); saveDeviceInfo(convertDeviceInfoDTO(entity)); LOGGER.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, r.toString()); } else { LOGGER.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, args[i]); } } } catch (Exception e) { LOGGER.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString); } // result的值就是被拦截方法的返回值 Object result = pjp.proceed(); LOGGER.info("请求结束,Controller的返回值是 " + result); return result; } /** * 将请求设备参数信息转换为设备对象 * * @param entity E * @return T */ private DeviceinfoDTO convertDeviceInfoDTO(IMReqeustEntity entity) { try { DeviceinfoDTO deviceinfoDTO = new DeviceinfoDTO(); deviceinfoDTO.setCity("河南省"); return deviceinfoDTO; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 前端请求的入参信息转换为设备对象 * * @param entity e * @return T */ private Deviceinfo saveDeviceInfo(DeviceinfoDTO entity) { try {// Deviceinfo deviceinfo = deviceinfoRepository.// save(EntityAndDTO.convert(entity, Deviceinfo.class));// return deviceinfo; } catch (Exception e) { e.printStackTrace(); LOGGER.error("保存设备信息异常,原因:" + e.getMessage()); } return null; }}