关于plupload跨域文件上传
现在基于Vue的前后端分离项目已经数不胜数,特别是在移动端中的应用。
在开发项目的过程中也遇到过许多问题,例如在前后端分离当中避免不了的跨域问题,关于 CROS(Cross-Origin Resource Sharing) 的介绍就不再这里进行赘述,不了解的赶紧去补充一下相关知识吧。
难得的空闲终于来了,今天记录一下之前遇到的关于 Plupload 的跨域问题。
区分用户身份的问题
对于POST跨域传递数据,服务端只需设置好 Access-Control-Allow-Origin 相应头即可。但是,如果需要区分不同用户,那就必须要携带Cookies,但是先看看下面这句:
1 | Fetch 与 CORS 的一个有趣的特性是,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。 |
注意这一句:对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息
也就是说,Plupload 在这种跨域、同时是POST的情况下,是没办法发送身份凭证信息的,那么问题就来了,如果相关后端接口需要对用户权限进行判断(例如根据用户权限控制是否允许用户上传),那该如何是好?
方案一:通过参数传递 PHPSESSID
既然不能携带Cookies,那为什么不能通过 GET 或者 POST 携带 PHPSESSID 传参实现呢?
思路很简单:
- 通过 Javascript 获取 Cookies 中的 PHPSESSID
- 通过 Request Body 或者 Request Params 将 PHPSESSID 传入服务端,服务端再切换当前会话,下面是在PHP实现的示范代码:
1 | // 以下代码中通过 `$_GET` 以及 `$_SESSION` 并不提倡,为安全性考虑请结合开发框架进行参数过滤 |
缺点
- 如果PHPSESSID设置为httponly,那么将无法通过Javascript获取到,如果需要强制使用则必须关闭,那么将以牺牲安全性为代价
- 同时采用该方案还要求前端和后端必须在相同父域的情况下,否则例如
web.com
和api.com
这样部署将无法采用该方案 - 或者类似于微信小程序的模式,用户凭据通过Request Params或者Request Body传递,不再有Cookies的概念,但对于已经有一定体系结构的项目,意味着前端或者后端都有较大的改动,所以也不是特别推荐。
严格来说这第一个甚至算不上一个方案,牺牲安全性、过程繁杂,emmm……
方案二:在CROS请求中携带Cookies
还是回到上方提到的链接:附带身份凭证的请求
Fetch 与 CORS 的一个有趣的特性是,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。
利用这个特性,即可解决文章开头所述的问题,至于Browser和Server只需要控制一下各自响应头即可,本文重点要说的是,在 Plupload 中该如何处理。
在这里直接贴上项目WIKI链接:https://github.com/moxiecode/plupload/wiki/Required-Features
其中 send_browser_cookies
就是我们需要的,不多说,直接上代码:
1 | const uploader = new plupload.Uploader({ |
关键点就是 send_browser_cookies
。
注意事项
- 对于附带身份凭证的请求,服务器不得设置
Access-Control-Allow-Origin
的值为*
。这是因为请求的首部中携带了 Cookie 信息,如果Access-Control-Allow-Origin
的值为*
,请求将会失败。而将Access-Control-Allow-Origin
的值设置为http://foo.example
,则请求将成功执行。
缺点
暂时还没想到,对于方案二的缺点欢迎大家留言提出
写在末尾
其实CROS跨域非常容易实现并解决,本文主要说的便是 withCredentials 携带Cookies的问题。
同时附赠在使用 vue-resource 的携带Cookie的方式:
1 | // 利用 Interceptors 特性在全局进行配置 |
在 axios 中如何配置欢迎各位提供代码,这边没有实际测试就不贴代码了,不过参考链接请看,看完就知道该怎么做了:https://github.com/axios/axios#config-defaults