跨域!什么玩意?为什么要我们后端来配置?
小乐刚刚入职公司不久,是一位年轻有为的后端程序员。
一天,他正专心致志地写着自己的逻辑代码,突然接到了一个通知。
"嘟嘟嘟..."手机响起来。
小乐看了一眼屏幕,是项目组的群里发的消息:
"小伙伴们,项目需要解决跨域问题,后端小伙伴们准备配置一下吧!"
小乐一脸懵逼,抬头看了看身边的同事们,有的在敲键盘,有的在调试接口,一片忙碌的景象。
他小心翼翼地问旁边从事后端十年的同事小来。
"前辈,这个跨域是啥啊?为啥是我们后端来搞?"
小来笑着解释道:
"小乐,跨域是因为浏览器的一种机制,导致浏览器不能接收到咱们后端返回的数据信息了。"
小乐挠了挠头,有些迷糊:
"哦,原来是浏览器的锅,那为啥不是前端去搞呢?"
小来笑眯眯地说:
"你怎么现在就开始搞前后端责任推卸了,这样可成为不了一名好的程序员,虽然说前端也可以搞,但是后端搞跨域问题是出于很多原因的考虑的,比如说:安全性、可控性、兼容性等等。所以你这次配置就交给你吧!你回去了解一下吧 ~"
小乐急忙回复到:
"可是我现在手上的活都还没做完,估计今晚还得加班呢!跨域问题,我真没时间呀!"
小来边走边说道:
"没事儿,年轻人嘛,多锻炼锻炼,加加班,主要想让你多学习学习。那就这样,我们几个先走了!你一会加班完之后记得关灯!"
什么是跨域?今天高低得把跨域给拿捏了。
小乐苦笑着打开搜索引擎,准备今天通宵学习有关跨域的知识。说着在浏览器上打字:
"什么是跨域?"
- 跨域 (Cross-Origin) 是指在浏览器的同源策略(Same-Origin Policy)下,一个网页的源(指协议、域名、端口号的组合)与另一个网页的源不同。因此,不同源的网页之间受到限制,无法直接进行通信。
- 同源策略(Same-Origin Policy)是一种由浏览器实施的安全机制,旨在限制一个源(指协议、域名、端口号的组合)的网页在脚本中如何与另一个不同源的资源进行交互。该策略的主要目的是防止潜在的恶意网站通过脚本访问用户的敏感信息,增强浏览器的安全性。
- 具体而言,同源策略限制了通过脚本访问不同源的文档、Cookie、LocalStorage 等资源。当一个网页尝试在脚本中请求另一个不同域的资源时,浏览器会阻止这个请求,以保护用户的隐私和防范潜在的安全威胁。
"哦哦哦,原来是这样,我大概理解了,就是说,
在一个完整的项目中,各个网页之间可以方便地进行信息通讯,因为它们属于同一个"家族"(同一个源)。在过去,前后端没有分离的时候,这种问题并不突出,因为所有的页面都是在同一个"家"里。然而,随着前后端分离的兴起,不同的网页可能属于不同的源,就像分开住在不同的地方一样。这就导致了浏览器的同源策略,它会认为从其他地方来的数据可能是不安全的,从而进行一些安全限制和警告。虽然这对于保护用户的数据安全很重要,但是前后端的通讯就成为了一个问题。 "
后端如何解决跨域问题呢?
"那需要如何解决呢?"
小乐一脸憔悴。灵机一动。
于是赶紧打电话给同样正在加班的不同公司的小昂(比自己早毕业一年的学长也是程序员)。
"小昂学长,我司....,请问你有好的解决办法吗?"
小昂学长回道:
"我给你发过去一个文档,里边资料很详细,你参考参考吧!对了,听说你最近胸肌又练大了,改天请你吃饭,我们交流交流。"
"啊,那什么,我先看看文档,学长改天请你吃饭。"
小乐赶忙挂断电话。打开文档。
后端SpringBoot如何优雅的解决跨域问题
在Spring Boot中解决跨域问题有三种主要办法:
1、使用@CrossOrigin
注解: 在控制器类或方法上使用@CrossOrigin
注解,指定允许的域名、请求方法等。这是一种简单直接的方式。
java
/**
* 在控制器方法或类上使用 @CrossOrigin 注解,指定允许跨域的配置。
*
* @param origins 允许访问的域名,可以使用通配符 "*" 表示允许所有域名访问。
* @param maxAge 预检请求的缓存时间,单位为秒。在此时间范围内,浏览器无需再次发起预检请求。
*/
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:8081", maxAge = 3600)
public class MyController {
// 控制器方法
}
origins
: 指定允许访问的域名。可以是一个具体的域名,也可以使用通配符 "*" 表示允许所有域名访问。在示例中,只允许来自http://localhost:8081
的域名发起跨域请求。maxAge
: 预检请求的缓存时间,单位为秒。预检请求是一种 CORS 机制中的预检查步骤,用于确认实际请求是否安全。maxAge
指定了浏览器可以缓存预检请求的时间,即在这个时间范围内,浏览器无需再次发起预检请求。在示例中,设置为 3600 秒(1 小时)。
2、配置全局跨域规则: 创建一个配置类,继承WebMvcConfigurerAdapter
,重写addCorsMappings
方法,配置全局的跨域设置。
java
/**
* 跨域配置类,继承自 WebMvcConfigurerAdapter。
*/
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
/**
* 重写 addCorsMappings 方法,配置全局的跨域设置。
* @param registry CorsRegistry 对象,用于配置跨域规则。
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 针对路径 "/api/**" 配置跨域规则
registry.addMapping("/api/**")
// 允许访问的域名,可以使用通配符 "*" 表示允许所有域名访问
.allowedOrigins("http://localhost:8081")
// 允许的请求方法,如 GET、POST、PUT、DELETE
.allowedMethods("GET", "POST", "PUT", "DELETE")
// 是否允许携带凭证信息(如 Cookie)
.allowCredentials(true)
// 预检请求的缓存时间,单位为秒。在此时间范围内,浏览器无需再次发起预检请求
.maxAge(3600);
}
}
3、使用Filter进行跨域设置: 创建一个CorsFilter
过滤器,配置跨域规则,然后在WebApplication
中注册这个过滤器。
java
/**
* 自定义 CorsFilter 类,继承自 OncePerRequestFilter,用于配置跨域过滤器。
*/
@Component
public class CorsFilter extends OncePerRequestFilter {
/**
* 重写 doFilterInternal 方法,处理跨域配置逻辑。
* @param request HttpServletRequest 对象,表示 HTTP 请求。
* @param response HttpServletResponse 对象,表示 HTTP 响应。
* @param filterChain FilterChain 对象,表示过滤器链。
* @throws ServletException 如果发生 Servlet 异常。
* @throws IOException 如果发生 I/O 异常。
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 设置允许访问的域名为 "http://localhost:8081"
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
// 允许的请求方法,如 GET、POST、PUT、DELETE
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// 允许的请求头,如 Content-Type
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
// 是否允许携带凭证信息(如 Cookie)
response.setHeader("Access-Control-Allow-Credentials", "true");
// 预检请求的缓存时间,单位为秒。在此时间范围内,浏览器无需再次发起预检请求
response.setHeader("Access-Control-Max-Age", "3600");
// 继续执行过滤器链
filterChain.doFilter(request, response);
}
}
OncePerRequestFilter
: 保证在一次请求中只执行一次过滤的基类。doFilterInternal
: 重写父类的方法,处理跨域配置逻辑。response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081")
: 设置允许访问的域名为 "http://localhost:8081"response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
: 允许的请求方法,如 GET、POST、PUT、DELETE。response.setHeader("Access-Control-Allow-Headers", "Content-Type")
: 允许的请求头,如 Content-Type。response.setHeader("Access-Control-Allow-Credentials", "true")
: 是否允许携带凭证信息(如 Cookie)。response.setHeader("Access-Control-Max-Age", "3600")
: 预检请求的缓存时间,单位为秒。在此时间范围内,浏览器无需再次发起预检请求。
后记
第二天小乐顶着大大的黑眼圈来到公司,然后骄傲的告诉同事,说道:
"这个跨域问题已经解决了,非常简单,so easy"
同事小来随口来了一句:
"Nginx配置我已经更新了,刷新一遍就好了。这个问题已经解决了,看你加班严重,我早上来三分钟搞定了,没你事儿了。你忙你的吧。"
小乐惊讶说道:
"啊!! 我也配好了,在代码中配的,就等着上测试和预生产呢!"
同事们都转过头看小乐:
"她要上生产吗?最近有版本要升级吗?好像没有吧,最近一次都在下周吧。"
.....
总结
一定要多思考,如果人永远待在舒适圈的话,人永远不会成长。共勉。
觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა