OA系统开发(前后端分离,前端vue2,后端aiohttp)(-)跨域问题
项目前端采用vue2框架,UI主题框架采用Vue Material ,table框架采用了easytable,与后端连接采用了axios。
后端主题框架采用了aiohttp,由于前后端分离涉及跨域,token验证等服务,所以对aiohttp做了一定的封装,并且涉及orm 及数据缓存等技术。
这篇文章主要记录开发过程中所遇到的问题及解决方案。
一 跨域问题
跨域涉及简单跨域和复杂跨域两种
简单跨域(Simple Requests)
我们定义一种 request 叫 simple request,当且仅当一个 request 满足下面全部条件的时候:
request method 只能是 GET,HEAD,POST
只能有浏览器默认添加的 headers,以及一些 CORS 协议中默许的 headers 比如 Accept 等,更多被允许的 headers,可以看这里
Content-Type这个header的value只能是特定的3个
在 js 代码中不要使用特定的方法,可参见文档
一旦一个 request 是 simple request,那么,尽管这个请求是跨域的,它也会被浏览器直接放行。但是,在 response 返回的时候,浏览器并不会把 response 直接交给你,而是去检查这个 response 的 headers 中有没有 Access-Control-Allow-Origin,以及这个 header 的 value 包含 request 发出的地址(也就是“域”)。
如果两个条件都满足, response 会被返回给发出请求的程序;如果没有这个 header 或者 value 不对, response 就会被拦截下来,因为在浏览器看来,这个 response 不属于你(因为服务器没有明确允许你这个“域”来请求它)。如果你使用的是 chrome 浏览器,在 response 被拦截下来的时候,console 中会显示一个类似于下面的错误信息:
repeat this in your console
尽管发出request的程序无法得到 response,但是这个请求实际上是被发出了的,而且服务器也会完整的处理这个request。可以想见,如果被请求的服务器支持被跨域请求,那么它一定会想办法在 response 中加上Access-Controll-Allow-Origin这个 header,并且附上合适的值。什么是合适的值呢?在 Request 的headers中会有一个 Origin,只要Access-Controll-Allow-Origin包含这个 Origin 就可以了(如果是 wildcard *,那么就等于包含所有的 Origin)。
复杂跨域(Preflighted Requests)
进行跨域的请求只会被分为两类,第一类就是 Simple Requests,其他的都是 Preflighted Requests。所以,只要一个请求,不满足上面一小节中对 simple requests 的要求,就是 preflighted requests 了。也就是说,一个请求只要满足下面几个条件中的任意一个就可以被划归此类了:
不是 GET,HEAD,POST 请求;比如是 PUT 请求
包含一些非 CORS 协议默许的 headers,比如Authorization,X-Request-With 或者一些自定义的headers。
Content-Type 不是默许的那 3 种
在 js 代码中使用了特定的方法,可参见文档
看完了 preflighted requests 的入选条件,我们再来从字面和行为上理解一下这种跨域请求。preflight 的中文意思是起飞前的,而 preflighted 的意译可能是:被在起飞前搞了一番的(有点蹩脚,哈哈)。这种跨域请求的实际行为也确实包含 preflight (起飞前)的部分:在一个请求被发出之前,浏览器会先发一个 OPTIONS 请求到目标“域”的服务器上,这个提前发出的请求,被称为 preflight request。
讲完了 preflight request 这个最重要的概念,我们可以比较方便的梳理这种跨域请求的流程:
浏览器发送 preflight request(那个 OPTIONS 请求[2])
浏览器收到 preflight response(也就是刚刚那个 request 的返回)
浏览器根据 preflight response 中的 Access-Control-Allow-Origin, Access-Control-Allow-Headers以及其他Access-Control-*类的headers 中的 value 来判断网页程序真正要发出的 request 是否符合要求
如果这个 request 符合要求,request 被发出,网页程序可以收到正常的 response(如果不出网络通讯上的意外);如果这个 request 被判定为不符合要求,这个 request 干脆就不会被发出。