跨域--通过代码一步一步了解其本质
跨域无论日常工作还是面试都会遇到。网上充斥着各种资料,但大多数资料都是重理论,没有实际的代码的支持,这篇文章从代码出发,轻理论重实践的讲解跨域。
我们会使用koa搭建一个本地服务器:http://127.0.0.1:3200。 使用webpack启动本地客户端:http://127.0.0.1:3000。 探究一下前后端分离项目怎么支持CORS(跨域资源共享)。完整代码我放到了git上,阅读readme获取正确姿势。文章的主要内容如下:
- 跨域的基础知识
- koa搭建服务器
- kao中间件处理跨域
跨域的基础知识
关于跨域的基础知识,阮一峰老师有博客: 跨域资源共享 CORS 详解介绍得很清楚,接下来我通过图文简单介绍一些理论知识。
同源策略
跨域的反面就是同源。当协议、主机、端口相同的时候就是满足同源。
这次搭建的例子由于端口不同,所以客服端请求的时候我们就会遇到熟悉的错误。
Access to XMLHttpRequest at 'http://127.0.0.1:3000/user' from origin 'http://127.0.0.1:3200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
两种请求及CORS策略
了解了同源策略,我们聊聊请求。请求有复杂请求,也有简单请求。两种请求浏览器策略也不一样。一下列举了两种请求的一些例子:
- 简单请求:请求方式为get/post
- 复杂请求:请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json
简单请求的跨域策略如下图
- 客户端发送简单请求
- 请求头带上字段Origin表明来源
- 服务器收到请求,在响应头设置字段:Access-Control-Allow-Origin,用于告诉客服端是否可获取资源(*表示所有来源都可以)。
- 跨域资源共享完成
复杂请求的跨域策略如下图
- 客户端发起复杂请求
- 对于复杂请求首先发送一个预检请求,请求你式为options
- 服务器接受预检请求,设置Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers
- 三个字段告诉客户端:哪些来源允许跨域,哪些请求方式允许跨域,哪些请求头允许跨域。
- 客户端得到上诉信息,判断是否满足条件。满足条件,发起正式请求,跨域成功。
代码实现
了解了以上理论信息,下面我们进入实践环节。看看koa应该怎么写代码。
服务端
首先使用koa/koa-router搭建一个简单的服务器。
const Koa = require('koa')
const Router = require('koa-router')
const router = new Router() // 路由
const app = new Koa() //创建服务器实例
router.get('/name', async (ctx) => {
ctx.body = {
name: 'miujg',
age: 26
}
})
app.use(router.routes())
app.use(router.allowedMethods()) // 注册路由
app.listen(3000, ()=>{
console.log('serve start on 3000')
})
客户端
我这里客户端是使用webpack、webpack-dev-server启动的一个服务。发起请求js代码如下
const axios = require("axios")
axios.get('http://127.0.0.1:3000/name').then(rs => {
console.log(rs)
})
实际效果如下:
简单请求中间件设置
由之前的理论知识我们可以知道,对于简单请求,如果服务器在响应头中设置Access-Control-Allow-Origin,就能达到效果。
这时我们就会想到koa的中间件,中间件的目的是在响应头上设置Access-Control-Allow-Origin字段
代码实现如下:
const Koa = require('koa')
const Router = require('koa-router')
const router = new Router()
const app = new Koa()
// 简单请求跨域处理
app.use(async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*') // *标识允许所有来源,也可以设置数组
next()
})
router.get('/name', async (ctx) => {
ctx.body = {
name: 'miujg'
}
})
app.use(router.routes())
app.use(router.allowedMethods())
app.listen(3000, ()=>{
console.log('serve start on 3000')
})
请求效果如下:
可以发现响应头中设置了Access-Control-Allow-Origin,简单请求跨域资源共享成功。
复杂请求中间件设置
在以上代码的基础上,我们发起一个put请求。put为一个复杂请求
axios.put('http://127.0.0.1:3000/name').then(rs => {
console.log(rs)
})
后端加一个put接口
router.put('/name', async (ctx) => {
ctx.body = {
name: 'miujg--put',
age: 29
}
})
实际情况如下:
直接看报错:put方法不被允许,需要在options响应头中添加字段Access-Control-Allow-Methods。我们改造一下中间件:
app.use(async (ctx, next) => {
ctx.response.set('Access-Control-Allow-Origin', '*')
if(ctx.request.method == 'OPTIONS') {
ctx.status = 204
ctx.response.set('Access-Control-Allow-Methods', ['GET', 'PUT', 'POST', 'DELETE'])
ctx.response.set('Access-Control-Allow-Headers', ['Content-Type', 'Accept'])
}
next()
})
浏览器效果如下:
备注:不同的复杂请求,响应头设置的值也可能不一样。
到此我们从代码层面搞清楚怎么处理跨域了,在实际开发中,只需要引进koa-cors就行了。这里就不多介绍。
小结
要深刻理解跨域,首先要搞清楚理论知识,知道浏览器的跨域资源共享是一个怎么策略。然后本地模拟客户端和服务器,在火狐浏览器中看效果。我相信,有了编码这个过程,你能更深刻理解跨域。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!