前端每时每刻都是在和页面打交道,管你是 h5 还是在 PC 端的页面;然而,在页面上的数据处理多种多样,但现在为了页面的交互性,大多数时候都会使用 ajax 在需要的时候对我们的数据进行处理 (获取数据、提交表单数据、上传图片信息等)。本文主要记录自己在实际项目中上传图片遇到的跨域问题。
实际场景
需求主要是一个话题互动页面,在评论框中需满足能够上传图片的要求,需求看似平平常常,处理起来也没什么太大的问题,那就开干吧。
页面依赖的插件
- zepto.js
- plupload.js
实际场景的代码片段
- html 提供评论框中的 dom 结构
1 | <div class="post-reply-modal-uploadimg j-post-reply-modal-uploadimg"> |
- JavaScript 初始化 plupload 上传图片插件事件
1 | function uploadImg() { |
上面的初始化及配置有疑问可以查看 plupload主页,上面的过程很简单,没多久就搞定了,那就实际测一测呗;…………我擦,为什么上传图片到服务器不成功?
API 跨域问题
一个域名地址的组成:
http:// | www. | xxx.com | :8080 | files/filsname |
---|---|---|---|---|
协议 | 子域名 | 主域名 | 端口号 | 请求资源地址 |
当协议、子域名、主域名、端口号中任一不相同时都不能算做同域,在不同域之间互相请求资源时就算作‘跨域’。
ok,最终的重点记录还是这后面的,那就记录记录为什么上传图片到服务器不成功咯。
很明显,这就是跨域嘛,跨域处理的情况那不是挺多的,那就解决一下吧。
常见的 jsonp 跨域
虽然在页面上调用不同域的接口不被允许,但是调用不同域的资源(如js脚本)是被允许的,jsonp 则正是利用这个特性来进行跨域数据请求处理。比如在 a.html 页面上,它里面的代码需要利用 ajax 获取不同域上的 json 数据,假设数据地址是 http://b.com/data.php,那么 a.html 中的代码可以这样:1
2
3
4
5
6<script>
function doSomething(jsonData) {
// 处理获取的 json 数据
}
</script>
<script src='http://b.com/data.php?jsonpcallback=doSomething'></script>因为后端代码是当做一个js文件来引入的,则它必须返回的是一个能执行的js文件,即后端代码如下:
1
2
3
4
5<php?
$jsonpcallback = $_GET['jsonpcallback'];
$data = array('a', 'b', 'c');
echo $jsonpcallback.'('.json_encode($data).')';最终页面上会输出doSomething([‘a’,’b’,’c’]),即这样我们就可以通过jsonp获取跨域的请求数据了。
XHR2(html5)处理跨域方式
html5提供的XMLHttpRequest Level2已经实现了跨域访问以及其他的一些新功能,这个功能就很方便,在所有的现代浏览器中基本上已经全部支持,如果是开发 h5 页面的话基本上不用考虑支持的问题;在使用的时候客户端不用做任何事情,只需要服务端修改支持跨域的几个请求头即可:1
2
3
4'Access-Control-Allow-Origin':'*'
'Access-Control-Allow-Credentials':'true'
'Access-Control-Allow-Headers':'x-requested-with'
'Access-Control-Allow-Methods':'POST, GET, OPTIONS, PUT, DELETE, HEAD'这些请求头设置可以根据自己的需要按需设置。
还有更多的跨域方式这里不在主要的记录范围,有时间再记录跨域的东西吧。。下面继续记录本次的 api 跨域遇到的坑。
本次上传图片跨域问题处理
通过前面的步骤其实已经大致记录了本次处理跨域的一个方法方向,因为主要是在移动端的页面,则直接采用了最新的XHR2跨域的处理方式,后端修改支持即可;难道这就完美了,答案肯定不是,不然怎么会有坑,由于奇葩的测试环境和线上环境,这里的跨域在当前梳理的时候一直不能成功,检查:
后端添加允许跨域已完成:1
2
3
4'Access-Control-Allow-Origin':'特定的网站地址'
'Access-Control-Allow-Credentials':'true'
'Access-Control-Allow-Headers':'x-requested-with'
'Access-Control-Allow-Methods':'POST, GET, OPTIONS, PUT, DELETE, HEAD'讲道理,前端此时不需要做其他设置是能够成功发送请求的,但是这里就是不讲道理;和后端沟通后得知,请求已经成功,但是他们的验证用户是否登录是直接校验的请求带回的 cookie 中是否有用户标识,oh my god,看一下呗。
好吧,这里根本没有 cookie 带回去,但是通过浏览器的检查工具查看 cookie 确实是存在的,信息敏感,删除所有信息留一个只做记录用;
那么这有关乎到 cookie 的问题了,很容易想到,cookie 本来在请求是是会自动将值带上的,但是在域不同的时候肯定是不会自动将值加入,那么这里就是这个原因造成的呗,在js代码中处理了一波 cookie 的 domain 是允许跨域的地址后再次发起请求,结果显而易见,肯定是失败了,不然我就不做这次尴尬的记录了。。图片如下:
- 额,这里又出现了一个 option 请求,什么情况;
option 请求简单理解:例如在接口发起post请求处于跨域情况下,首先会自动发送一个option请求到服务器进行确认,问服务器兄弟,我本次请求你允许我操作吗?如果服务器告诉它,兄弟,可以的,那么就再发起一次本来是post请求到服务器且服务器返回成功信息,若服务器不允许,那么这里就拜拜咯,下面的操作仍然不能继续;这里有一个需要注意的点,这个时候前端是无能为力的,需要后端将option请求的操作进行一个处理,让此操作也能成功跨域(后端哥哥操作,不了解,不跟任何步骤,只记录需要他们处理),并且上图中的 origin 一定注意,也要设置成允许跨域的地址(允许所有就是*,特定某个地址就设置成具体的某个地址)。这一步踩坑一下午……… ^–^ - 最终结果
在前面的坑走过一遍后,终于能够将本次跨域所设计的问题基本解决。
总结
跨域的方法很多,但是每个公司及当前处理环境可能各不相同,最重要的还是一套成熟的规则吧;上述在理解上肯定不全面,欢迎各位大佬批评指正……