当前位置: 首页 > 科技观察

配置跨域后,框架为我们做了什么?

时间:2023-03-19 10:32:07 科技观察

跨域问题现在公司大部分项目都是前后端分离的。前后端分离后,必然会出现跨域问题。如下图继续调试,发现response是undefined,提示信息是NetworkError。所以在和前端联调的时候,请求一直失败,报网络错误。一般后端没有做过跨域配置。注意此时不是后端没有收到请求,而是收到了请求并返回了结果,但是浏览器截取了结果并报错。同源策略那么为什么浏览器会报错呢?因为浏览器基于安全考虑引入的同源策略,当协议+域名+端口相同时,不会出现跨域问题,即同源。这时候就可以读取到服务器的响应了。当前url请求url是否跨域https://www.javashitang.comhttp://www.javashitang.com是的,协议不一样https://www.javashitang.comhttp://book.javashitang.com是的,域名不一样https://www.javashitang.comhttp://www.javashitang.com:8000是的,端口不一样。为什么要有同源策略?当然,出于安全考虑,比如以银行转账为例,看看你的钱是怎么跑的。这就是著名的CSRF攻击(跨站请求伪造,当然还有很多其他方式),如果在第5步中没有验证请求的来源,那么你的钱就被转移了。允许html页面中的以下三个标签跨域加载资源。标签发送请求来实现数据的加载,但是这种方式有个缺点,就是只能支持GET请求,其他请求是不能支持的,因为很少用到JSONP方式,所以就不过多介绍了。CROS不是一个简单的请求。在正式跨域请求前,发送一个OPTIONS请求询问服务器是否接受下一次跨域请求,携带如下headerOrigin:请求的原域Access-Control-Request-Method:跨域的方法-要发起的域请求(GET/POST/…)Access-Control-Request-Headers:要发起的跨域请求中包含的请求头字段服务器在返回中添加如下头,表示本次跨域请求是否通过允许域请求。浏览器收到后进行检查,如果不符合要求,则不会发起后续请求。Access-Control-Allow-Origin:允许哪些域访问(*表示允许所有域的请求)Access-Control-Allow-Methods:允许哪些请求ModeAccess-Control-Allow-Headers:哪些请求头字段是否允许Access-Control-Allow-Credentials:简单的带cookies的请求,每次都要发送二次请求,是不是很麻烦?所以它被优化了。当请求方法为HEAD、GET、POST且请求头只有以下内容时,定义为简单请求AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:(application/x-www-form-urlencoded,multipart/form-data,text/plain)简单请求会在请求中加上Origin头,直接发起请求,无需先询问。后端可以返回相应的header。Spring支持跨域,理解跨域的本质。看各种配置,其实就是根据request给response加上headers。使用Filter配置如下Filter,CrossDomainFilter是对javax.servlet.Filter的封装,本质上是一个Filter。可以看到我又返回了一个header,Access-Control-Max-Age,表示查询结果的有效期,也就是在3600s以内,浏览器不需要询问@Component@WebFilter(filterName="crossDomain",urlPatterns="/*")publicclassCrossDomainFilterextendsOncePerRequestFilter{@OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{//此处可以进行白名单检测if(CorsUtils.isCorsRequest(request)){response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));response.setHeader("Access-Control-Allow-Credentials","true");response.setHeader("Access-Control-Allow-Headers",request.getHeader("Access-Control-Request-Headers"));response.setHeader("Access-Control-Allow-Methods",request.getHeader("Access-Control-Request-Method"));response.setHeader("Access-Control-Max-Age","3600");}//是一个OPTIONS请求,header已经设置好,不需要执行后续逻辑,直接执行如果(CorsUtils.isPreFlightRequest(request)){return;}filterChain.doFilter(request,response);}}查看使用的工具类publicabstractclassCorsUtils{//如果请求中有origin的header,则返回truepublicstaticbooleanisCorsRequest(HttpServletRequestrequest){return(request.getHeader(HttpHeaders.ORIGIN)!=null);}publicstaticbooleanisPreFlightRequest(HttpServletRequestrequest){return(isCorsRequest(request)&&HttpMethod.OPTIONS.matches(request.getMethod())&&request.getHeader(HttpHeaders!STTR_MEOL_CONTHERQ_)}使用CorsRegistry@ConfigurationpublicclassGlobalCorsConfig{@BeanpublicWebMvcConfigurercorsConfigurer(){returnnewWebMvcConfigurer(){@OverridepublicvoidaddCorsMappings(CorsRegistryregistry){//添加映射路径registry.addMapping("/**")//允许域.allowedOrigins("*允许携带cookies。allowCredentials(true)//允许的请求方法.allowedMethods("GET","POST","PUT","DELETE")//允许的请求headers.allowedHeaders("*");}};}}使用@CrossOrigin支持注释t更细粒度的配置,你可以使用Method方法或类@RestController@RequestMapping("resource")@CrossOrigin({"http://127.0.0.1:8080"})publicclassResourceController通过其他方式支持跨域看到这里你可能会有疑惑,我们的项目中没有中的跨域配置,怎么才能支持跨域呢?那大概就是把设置header的工作交给gateway层吧。转载本文请联系爪哇石塘公众号。