ajax 跨域处理记录

前端每时每刻都是在和页面打交道,管你是 h5 还是在 PC 端的页面;然而,在页面上的数据处理多种多样,但现在为了页面的交互性,大多数时候都会使用 ajax 在需要的时候对我们的数据进行处理 (获取数据、提交表单数据、上传图片信息等)。本文主要记录自己在实际项目中上传图片遇到的跨域问题。

实际场景

需求主要是一个话题互动页面,在评论框中需满足能够上传图片的要求,需求看似平平常常,处理起来也没什么太大的问题,那就开干吧。

页面依赖的插件

  • zepto.js
  • plupload.js

实际场景的代码片段

  • html 提供评论框中的 dom 结构
1
2
3
4
5
6
7
8
9
<div class="post-reply-modal-uploadimg j-post-reply-modal-uploadimg">
<div class="plupload-content j-plupload-content">
<a class="plupload-content-btn j-plupload-content-btn" href="javascript:;"><!-- 上传的按钮dom --></a>
<p class="plupload-content-success j-plupload-content-success">
<img class="success-img j-success-img" src="" alt="">
<a class="delete-img j-delete-img" href="javascript:;"></a>
</p>
</div>
</div>
  • JavaScript 初始化 plupload 上传图片插件事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function uploadImg() {
const uploader = new plupload.Uploader({
runtimes: 'html5,html4,flash,silverlight',
browse_button: $('.j-plupload-content-btn'),
url: uploadImgAPI, // 在本地选择文件后通过请求上传图片信息到服务器的url
flash_swf_url: '../assets/scripts/upload/moxie.swf',
silverlight_xap_url: '../assets/scripts/upload/moxie.xap',
headers: {},
chunk_size: 0,
max_retries: 1,
file_data_name: 'file',
multi_selection: false,
multipart: true,
required_features: {
send_browser_cookies: true,
},

filters: {
mime_types: [
{ title: 'Image files', extensions: 'jpg,jpeg,png,gif' },
],
prevent_duplicates: false,
max_file_size: '10240kb',
max_file_count: 1,
},

init: {
Init: () => {
// 初始化执行的操作
},

FilesAdded: (up, files) => {
// 上传队列数据加载完后执行start对数据进行上传
uploader.start();
},

FileUploaded: (up, files, res) => {
// 在数据通过接口上传完后处理当前数据在页面上的显示
},

Error: (up, err) => {
// 上传图片过程中出现错误可以在这里操作
console.log('---', up, err);
},
},
});

uploader.init();
}

上面的初始化及配置有疑问可以查看 plupload主页,上面的过程很简单,没多久就搞定了,那就实际测一测呗;…………我擦,为什么上传图片到服务器不成功?

API 跨域问题

一个域名地址的组成:

http:// www. xxx.com :8080 files/filsname
协议 子域名 主域名 端口号 请求资源地址

当协议、子域名、主域名、端口号中任一不相同时都不能算做同域,在不同域之间互相请求资源时就算作‘跨域’。
ok,最终的重点记录还是这后面的,那就记录记录为什么上传图片到服务器不成功咯。

很明显,这就是跨域嘛,跨域处理的情况那不是挺多的,那就解决一下吧。

  1. 常见的 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获取跨域的请求数据了。

  2. 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 跨域遇到的坑。

  3. 本次上传图片跨域问题处理

  • 通过前面的步骤其实已经大致记录了本次处理跨域的一个方法方向,因为主要是在移动端的页面,则直接采用了最新的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 一定注意,也要设置成允许跨域的地址(允许所有就是*,特定某个地址就设置成具体的某个地址)。这一步踩坑一下午……… ^–^
  • 最终结果
    在前面的坑走过一遍后,终于能够将本次跨域所设计的问题基本解决。

总结

跨域的方法很多,但是每个公司及当前处理环境可能各不相同,最重要的还是一套成熟的规则吧;上述在理解上肯定不全面,欢迎各位大佬批评指正……