共计 3708 个字符,预计需要花费 10 分钟才能阅读完成。
跨域问题是前后端拆散我的项目中十分常见的一个问题,举例来说,编程学习网站的前端服务跑在 8080 端口下,后端服务跑在 9002 端口下,那么前端在申请后端接口的时候就会呈现跨域问题。
403 Forbidden 是 HTTP 协定中的一个状态码(Status Code),意味着后端服务尽管胜利解析了申请,但前端却没有拜访该资源的权限。
那怎么解决这个问题呢?通常有两个思路:
前端应用 Nodejs 代理(开发环境下,生产环境下能够用 Nginx 代替)
或者后端开启跨域资源共享
一、对于跨域
跨域对于前后端开发者来说,就像一块狗皮膏药,无论是面试还是开发中,都会常常遇到。
之所以呈现跨域问题,是因为浏览器的同源策略,为了隔离潜在的歹意文件,为了进攻来自旁门左道的攻打,浏览器限度了从同一个源加载的文档或脚本与来自另一个源的资源进行交互。
后面咱们提到了,前端跑在 8080 端口下,后端跑在 9002 端口下,这种状况就属于不同的源(域名不同,协定不同,端口不同),所以 8080 端口下的前端申请间接拜访 9002 端口下的后端接口时就拜访失败了。
那正确的打开方式是什么呢?咱们后面也提到了,前端应用 Nodejs 代理或者后端开启跨域资源共享,咱们一一来实际下。
二、Nodejs 代理
在 Nodejs 呈现之前,JavaScript 编写的程序通常须要在用户的浏览器上执行,Node.js 呈现后,JavaScript 也能用于服务端编程了。Nodejs 一系列的内置模块使得程序能够脱离 IIS、Apache 这种 Web 服务作为独立的服务器执行。
咱们应用 Nodejs 来解决跨域问题的思路就是,在本地创立一个虚构服务器,对 8080 端口下的前端申请进行代理,同时接管 9002 端口下的服务器端响应,这样服务端和服务端进行数据的交互就不会呈现跨域问题了。
第一步,配置 Nodejs 代理服务
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api': {
target: 'http://localhost:9002', // 你申请的第三方接口
changeOrigin: false, // 在本地会创立一个虚构服务端,而后发送申请的数据,并同时接管申请的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
pathRewrite: { // 门路重写,'^/api': '' // 替换 target 中的申请地址,也就是说当前你在申请 http://api.codingmore.top/v2/XXXXX 这个地址的时候间接写成 /api 即可。}
},
},
}
复制代码
第二步,配置前端拜访申请门路
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
VUE_APP_BASE_API: '"/api"'
// VUE_APP_BASE_API: '"http://localhost:9002"'
})
复制代码
第三步,重启前端服务
再次点击「登录」按钮,能够看到申请的 URL 产生了扭转,原来是 http://localhost:9002/users/l…,当初是 http://localhost:8080/api/use…。与此同时,能够看到多了一个 Remote Address,端口也是 8080,也就是说通过 Nodejs 的代理,前后端的交互在同一个源上面了,这样就不会产生跨域问题了。
同时,能够看失去,服务器端返回的状态码变成了 200,示意申请胜利。
三、开启跨域资源共享
跨域资源共享,也就是 Cross-Origin Resource Sharing,简拼为 CORS,是一种基于 HTTP 头信息的机制,通过容许服务器标识除了它本人以外的资源,从而实现跨域拜访。
第一步,开启 CORS 反对
在 Spring Boot 利用中,退出 CORS 的反对简略到不忍直视,增加一个配置类就能够了。
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();
// 设置你要容许的网站域名
config.addAllowedOrigin("http://localhost:8080");
// 容许跨域发送 cookie
config.setAllowCredentials(true);
// 放行全副原始头信息
config.addAllowedHeader("*");
// 容许所有申请办法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
复制代码
第二步,重启后端服务,再次点击登录按钮,发现申请曾经能够失常拜访了。
![上传中 …]()
本例中,后端返回 Access-Control-Allow-Origin: http://localhost:8080 就示意,跑在 9002 端口下的后端接口能够被 8080 端口的前端申请拜访。
如果容许所有域名进行跨域调用的话,只需扭转一行代码即可。
// 容许所有域名进行跨域调用
config.addAllowedOriginPattern("*");
// 设置你要容许的网站域名
// config.addAllowedOrigin("http://localhost:8080");
复制代码
对于 login 这种简略的申请来说,它们是不会触发 CORS 预检的,因而不须要在服务器端减少其余配置就能够了。那什么是简略申请呢?
1)申请办法是以下三种办法之一:
HEAD
GET
POST
2)HTTP 的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
那对于会触发 CORS 预检的非简略申请(比如说申请办法是 PUT 或 DELETE,或者 Content-Type 字段的类型是 application/json,或者申请音讯头蕴含了一些自定义的字段),该怎么办呢?
非简略申请在正式通信之前,会减少一次 HTTP 查问申请,称为“预检”申请。预检申请通过后,才会返回失常的响应内容。
![上传中 …]()
拿编程猫的文章治理页来举例,该页面会向后端发动一个 posts/queryPageable 的分页查问,该申请蕴含了一个自定义的音讯头 Authorization,于是浏览器认为该申请是一个非简略申请,而后就会主动发动一次 OPTIONS 申请,但因为咱们的 Spring Boot 我的项目整合了 SpringsScurity 平安治理框架,没有对 OPTIONS 申请放开登录认证,导致验证失败,文章分页申请的响应数据就没有返回回来。
第三步,通过以下代码给 OPTIONS 申请放行。
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity
.authorizeRequests();
// 容许跨域申请的 OPTIONS 申请
registry.antMatchers(HttpMethod.OPTIONS)
.permitAll();}
}
复制代码
再次重启后端服务,从新拜访文章列表接口,发现有响应数据了。
非简略申请必须首先应用 OPTIONS 申请办法发动一个预检申请到服务器端,以获知服务器是否容许该理论申请。” 预检申请“的应用,防止了跨域申请对服务器的用户数据造成未预期的影响。
咱们来通过两张图片简略总结一下预检申请的整个过程,第一张,发动 OPTIONS 预检申请:
第二章,发动正式申请:
最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163 互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点 star:http://github.crmeb.net/u/defu 不胜感激!
PHP 学习手册:https://doc.crmeb.com
技术交换论坛:https://q.crmeb.com