上传图片的那些事儿

1.仅支持高版本刘浏览器上传

var param = new FormData();
param.append('imgData', file);
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", uploadCompleteHandler, false);
xhr.addEventListener("error", uploadFailedHandler, false);
xhr.addEventListener("abort", uploadCanceledHandler, false);
xhr.open("POST", url);
xhr.send(param);


XMLHttpRequest

IE4.0时以ActiveX对象,Exchange Server小组首先开发,微软软公司发明,

Mozilla 1.0中实现了一个兼容的版本。
Safari 1.2中开始支持XMLHTTP,
Opera从8.0版开始也宣布支持XMLHTTP。

ie5-6使用的是ActiveX,而非XMLHttpRequest

1998年 XMLHTTP

2002年8月,XMLHttpRequest Level 2草案提出

创建兼容的XMLHttpRequest

var XMLHttp=null;
if (window.XMLHttpRequest)
{
XMLHttp=new XMLHttpRequest()
}else if (window.ActiveXObject)
{
XMLHttp=new ActiveXObject("Microsoft.XMLHTTP")
}

FormData

XMLHttpRequest Level 2 中新增接口

需求增加进度条功能

XMLHttpRequest中有一个upload对象upload是一个XMLHttpRequestUpload

var param = new FormData();
param.append('imgData', file);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgressHandler, false);
xhr.addEventListener("load", uploadCompleteHandler, false);
xhr.addEventListener("error", uploadFailedHandler, false);
xhr.addEventListener("abort", uploadCanceledHandler, false);
xhr.open("POST", url);
xhr.send(param);


https://segmentfault.com/a/1190000004322487

https://xhr.spec.whatwg.org/

需要支持跨域请求

方案:1.JSONP

方案2:CORS

jsonp仅支持get,PASS

CORS

全称: 跨域资源共享-Cross-origin resource sharing

服务器与浏览器共同实现

CORS兼容性

新需求:支持低版本浏览器

flash上传插件解决

市面上的上传插件如webUploader

自动切换上传方式,很方便

but

仅支持jq 1.10.0+的版本,万恶的1.6.4

选择SWFUploader

使用指南

Flash使用方式

方案2:swf放在服务器端,与结构同源,所以也支持跨域

方案1:swf放在自己项目中,使用crossdomain.xml

<?xml version="1.0" encoding="UTF-8"?>  
<cross-domain-policy>  
<allow-access-from domain="*"/>  
</cross-domain-policy>  

SWFUploader配置

setting = {
    debug: false,

    upload_url: url, //服务器接受文件路径
    flash_url: "swf?ver=" + Math.random(), //上传的swf文件路径
    //文件配置
    file_post_name: "imgData", //服务器接受的文件数据key值
    post_params: {
        sessionId: opts.param.sessionId
    }, //上传文件时带的参数
    file_types: "*.bmp;*.jpeg;*.jpg;*.gif;*.png", //文件类型过滤配置
    file_types_description: '浏览器图片格式', //上传文件类型描述
    file_size_limit: opts.fileSizeLimit, //指定要上传的文件的最大体积,可以带单位,合法的单位有:B、KB、MB、GB,如果省略了单位,则默认为KB。该属性为0时,表示不限制文件的大小。
    file_upload_limit: "200",
    file_queue_limit: "1",
    prevent_swf_caching: false,
    preserve_relative_urls: false,
    //按钮配置
    button_placeholder_id: opts.id,
    button_width: (opts.type == 'pop') ? 160 : 175,
    button_height: (opts.type == 'pop') ? 100 : 109,
    button_text: "<span></span>",
    button_text_style: "",
    button_text_left_padding: 0,
    button_text_top_padding: 0,
    button_action: SWFUpload.BUTTON_ACTION.SELECT_FILES,
    button_disabled: false,
    button_cursor: SWFUpload.CURSOR.HAND,
    button_window_mode: "transparent",
    custom_settings: {
        index: opts.index
    },
    // 事件
    file_dialog_start_handler: _self.fileDialogStart,
    file_queued_handler: _self.fileQueued,
    file_queue_error_handler: _self.fileQueueError,
    file_dialog_complete_handler: _self.fileDialogComplete,
    upload_progress_handler: _self.uploadProgress,
    upload_error_handler: _self.uploadError,
    upload_success_handler: _self.uploadSuccess,
    upload_complete_handler: _self.uploadComplete
}
var swfupload = new SWFUpload(setting);

准备上传

but

上传完没回返回数据,有木有

重要的坑

flash在IE中上传的文件类型为 Accept 类型为text/*

高版本中使用XHR Accept 类型为*/*

服务端默认为*/*,需要单独配置接受flash发送的请求类型

增加登录验证(cookie)

XHR与FLASH 居然都不会自动携带cookie

顿时感觉为什么坑会不断呢,没办法有坑继续吧

登录验证添加后发现上传失败

XHR

withCredentials

var param = new FormData();
param.append('imgData', file);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgressHandler, false);
xhr.addEventListener("load", uploadCompleteHandler, false);
xhr.addEventListener("error", uploadFailedHandler, false);
xhr.addEventListener("abort", uploadCanceledHandler, false);
xhr.open("POST", url);
xhr.withCredentials = true;
xhr.send(param);

server端也必须允许request能携带认证信息(即response header中包含Access-Control-Allow-Credentials:true

cookie也算一种认证

PS:要特别注意一点,一旦跨域request能够携带认证信息,server端一定不能将Access-Control-Allow-Origin设置为*,而必须设置为请求页面的域名。

Flash

手动控制把cookie添加到请求头,或

使用swfupload.cookies.js来自动写入

Flash与XHR的cookie都带过去,

BUT

XHR版本你发现还是不会触发Success

经过与研发一起排查发现,被登录拦截器又一次拦截了

经过我的排查发现这么一个神奇的事情

OPTIONS请求

 以为自己代码写错了,删除代码发现

多了这个监听就会发送OPTIONS请求:

xhr.upload.addEventListener("progress", _self.uploadProgress, false);

此为预检请求

触发预检请求的情况

1:使用了下面任一 HTTP 方法:

PUT

DELETE

CONNECT

OPTIONS

TRACE

PATCH

简单请求与复杂请求

触发预检请求的情况

2.人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:

 

触发预检请求的情况

 Content-Type 的值不属于下列之一:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

解决方法

研发端需要对请求类型过滤,当为OPTIONS时不需要进行cookie验证

THANKS

Made with Slides.com