前言
最近在做期末课程设计,当前端通过axios
向后端发请求时,发现报错了:
查阅了一番资料,发现这是跨域问题,这篇文章我们就来聊聊跨域问题以及解决方法。
跨域
是什么?
跨域(Cross-Origin)指的是在浏览器中,当一个网页的源(Origin)与正在请求的资源的源不相同时,就会发生跨域请求。
跨域通常发生在:后端响应回来的数据,在浏览器上被终止。即前端的请求后端可以接收到,只不过响应回去时被浏览器终止了。
为什么会出现跨域问题?
因为浏览器实施了同源策略(Same-Origin Policy)
,该策略限制了不同源之间的交互。
同源策略的目的是保护用户隐私和安全,防止恶意网站获取其他源上的敏感信息或执行未经授权的操作。
那什么是不同源呢?
URL
地址由三部分组成:协议号-域名-端口号(有一个不相同就是不同源)
举个例子:协议号为https
,域名为localhost
,端口号为3000
的URL地址与协议号为https
,域名为localhost
,端口号为8080
的URL地址因为端口号不同,所以他们是不同源的,就会出现跨域问题。
浏览器的同源策略虽然保障了安全,但是给我们程序员的开发带来了不便,有问题就有解决方法,接下来我们一起来看一下吧。
解决跨域的方法
JSONP
我们知道通过img
标签获取图片地址可以很容易的拿到图片资源,通过<script>
标签请求一些Js
也能获取到;像img
,<script>
标签从不同域名下加载静态资源,是被浏览器允许的。
原理
基于<script>
标签没有跨域限制,我们就可以动态创建script
,通过<script>
标签src属性向后端传一个函数名(callback
),前端再在window
上挂上这个函数;后端就在callback
函数中传参数,浏览器会把后端响应给前端的东西当做函数来执行。
细分以下几步
- 前端创建一个
script
标签,借助该标签的src属性朝后端发送请求,且前端在window
上声明一个函数(callback
),并将该函数名拼接在src属性的路径后面作为参数传递给后端。
<button id="btn">获取数据</button>
<script>
function jsonp(url, cb) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = `${url}?cb=${cb}`
document.body.appendChild(script)
//拿到了后端返回的一个函数
window[cb] = (data) => {
// console.log(data);
resolve(data)
}
})
}
let btn = document.getElementById('btn')
btn.addEventListener('click', () => {
jsonp('http://localhost:3000', 'callback').then(res => {
console.log(res);
})
})
</script>
此时页面上有一个按钮获取数据,点击后就能向后端发请求。
- 后端接收到前端的请求且获取到前端传递过来的函数名,将需要响应给前端的数据拼接在该函数的调用中(相当于作为实参传递)。
const koa = require('koa')
const app = new koa()
//传给前端的数据
const data = {
name: 'song',
age: '18'
}
const main = (ctx) => {
const { cb } = ctx.query
const str = `${cb}(${JSON.stringify(data)})` //向前端传参数
ctx.body = str
}
app.use(main)
app.listen(3000, () => {
console.log('项目已启动');
})
- 前端接收到后端的响应,相当于在执行
window
上声明的函数(callback
),该函数的参数就是后端响应回来的数据。
此时页面上就能拿到后端传过来的数据:
缺点
- 这种方法利用
script
标签巧妙地拿到了后端的返回数据,但是需要前后端相互配合,要不然完成不了。 - 只能发get请求,浏览器加载
Script
的scr属性默认是get请求,无法修改。
CROS
CROS
全称是”跨域资源共享”(Cross-origin resource sharing),CORS
需要浏览器和服务器同时支持。
原理
通过设置响应头,告诉浏览器不需要走同源策略的保护机制。
原生Js
写法:
const server = https.createServer((req, res) => {
res.writeHead(200, {
"Access-Control-Allow-Origin": '*'//被允许的源
})
res.end('hello cors')
})
server.listen(3000)
使用
我们想要使用它的话可以直接npm i @koa/cors
,然后const cors = require('@koa/cors')
引入到项目中,再直接use
就可以了:
app.use(cors({
origin: '可以发请求过来的源'
}))
CORS
已经成为主流的跨域解决方案,我项目中也是这样解决的。
小结
本篇文章简单介绍了跨域是什么以及两种解决跨域的方法,当然肯定不止两种解决方法,我们有机会下次聊。关注作者不迷路(╹▽╹)。现在好累好困,早点睡了~