专栏名称: 京东设计中心JDC
专业,创造力,激情,设计。京东用户体验设计部门,致力于创造更美好的电子商务购物体验。
目录
相关文章推荐
青塔  ·  筑梦建工,共创辉煌 | ... ·  2 天前  
青塔  ·  这所师范高校,力争更名! ·  2 天前  
高校人才网V  ·  燕京理工学院2025年人才引进计划 ·  5 天前  
高校人才网V  ·  南方科技大学2025年实验教学岗招聘公告 ·  1 周前  
51好读  ›  专栏  ›  京东设计中心JDC

JDC丨京东设计中心 - 图片上传进阶 VS 京东户簿实战

京东设计中心JDC  · 公众号  ·  · 2017-08-16 11:30

正文

由于现在身份比较敏感,所以很多情况下你在网购时都会涉及到需要实名认证,此时就需要上传身份证照片。为了让大家能够在任何情况下都可以进行实名认证,前端的上传工作必不可少,如何进行图片上传的功能呢?下面会一步一步的深入到上传的海洋中,让你畅游其中。

京东推出了整站京东户簿组件,来统一管理用户的实名认证信息。此组件支持不同业务线跨域接入并兼容到 IE7+ 的不同场景。 (黑科技) 上传的图片支持 OCR 图像识别,可以与输入的证件号码做匹配,防止随便录入信息。

户簿系统组件的界面如下图:

接下来我们来逐步深入的剖析一下此组件的是如何来实现的。上传主要使用了 Ajax 与 XMLHttpRequest(文章中简称为 XHR ) 技术来实现。Ajax 介绍以及背景请参考 Ajax 背景

(如不了解  XHR ,可参考 w3.org 的一些文章基础教程文章即可快速了解,可参考如下连接地址:https://www.w3.org/TR/XMLHttpRequest/.)

上传图片功能实现

代码实现:

1

2

3

4

5

6

7

8

var param = new FormData ();

param . append ( 'imgData' , file );

xhr = new XMLHttpRequest ();

xhr . addEventListener ( "load" , _self . uploadComplete , false );

xhr . addEventListener ( "error" , _self . uploadFailed , false );

xhr . addEventListener ( "abort" , _self . uploadCanceled , false );

xhr . open ( "POST" , url );

xhr . send ( param );

以上代码中,文件需要通过 FormData 来承载并通过 xhr 发送给服务端, FormData 会有哪些隐患呢?来看一下 XHR 的发展历程。

XHR 一开始只是微软浏览器提供的一个接口,后来各大浏览器纷纷效仿也提供了这个接口,再后来W3C对它进行了标准化,提出了 XHR 标准 。XHR 标准又分为Level 1 和 Level 2。

XHR Level 1 中,XHR 有以下三个缺点:

  • 只支持文本数据的传送,无法用来读取和上传二进制文件。

  • 传送和接收数据时,没有进度信息,只能提示有没有完成。

  • 受到 “同域限制” (Same Origin Policy),只能向同一域名的服务器请求数据。

XHR Level 2 新版本针对老版本做出了大幅改进:

  • 可以设置 http 请求的时限。

  • 可以使用 FormData 对象管理表单数据。

  • 可以上传文件。

  • 可以请求不同域名下的数据(跨域请求)。

  • 可以获取服务器端的二进制数据。

  • 可以获得数据传输的进度信息。

FormData 参数为 XHR Level 2  中新增接口,所以会存在或多或少的兼容性隐患问题,兼容下如下图:

(数据来源: caniuse.com)

根据以上的兼容性,基本上 IE10 以下的浏览器就不用考虑了。

进度条实现

在 XHR 对象中有一个存在这么一个对象:upload。(来个传送门: https://xhr.spec.whatwg.org/#the-upload-attribute

upload是一个XMLHttpRequestUpload,可以将代码优化成以下方法:

1

2

3

4

5

6

7

8

9

10

var param = new FormData ();

param . append ( 'imgData' , file );

xhr = new XMLHttpRequest ();

/*新增进度条监听函数*/

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

xhr . addEventListener ( "load" , _self . uploadComplete , false );

xhr . addEventListener ( "error" , _self . uploadFailed , false );

xhr . addEventListener ( "abort" , _self . uploadCanceled , false );

xhr . open ( "POST" , url );

xhr . send ( param );


跨域功能实现

针对以上需求,我们可以提供2种跨域解决方案: JSONP 与 CORS。

JSONP:实现原理参考: https://en.wikipedia.org/wiki/JSONP 。由于 JSONP 无法使用 post 请求,故 PASS。

CORS :全程“跨域资源共享”(Cross-origin Resource Sharing),也是一个 Level2 中新增加的功能。兼容性可参考 caniuse 中 Level2兼容性 . 以下提供一张截图

所以只能采用此种方式来支持跨域 post 请求的图片上传功能。

CORS 的 配置需要前端与后端共同来完成 ,服务器端需要配置可以访问接入的域。发送请求的时候也会在 http 的响应头中添加  Access-Control-Allow-Origin:*。

* 表明,该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:Access-Control-Allow-Origin: http://foo.example

低版本浏览器支持

身为前端开发人员,我相信大家此时都在诅咒微软为啥还不倒闭,微软已经严重的阻碍的大前端的发展脚步,但是抱怨归抱怨,用户群体还是很大的,只能想法来解决了。

根据以上的步骤其实 IE10+ 浏览器已经没问题了,但是因为使用了FormData,CORS 等一些 Level2 的新标准,所以无法再低版本浏览器更好的运行。

解决方案:使用 Flash 来支持低版本浏览器。

市面上比较好的插件有 webUploader ,可以根据浏览器类型来切换 flash 跟 XHR ,单因为此插件需要依赖于 jquery1.10+ 才可以,故无法使用。

最后使用了 SWFUploader 来支持,注:Flash 使用也是存在跨域问题的。

Flash文件的使用方式:

  1. swf放在自己项目中,创建一个 XML,将文件放在与接口同域的服务器上,Crossdomain.xml 文件内容如下,(以下例子为允许所有网站访问)

  1. 将 SWF 文件放在与接口同域的服务器上,使用对应 JS 引用 SWF 即可。

以上两种方式均可, SWFUploader 配置调用方式


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

0

31

32

33

34

35

36

37

38

39

40

41

42

43

var setting = {

debug : false ,

upload_url : url , //服务器接受文件路径

flash_url : 'flashurl/swfupload.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 : " " ,

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 : 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 )


函数配置好就行了,具体使用方式可以看一下文档: http://www.leeon.me/upload/other/swfupload.html

配置好以后,问题出现:发现在高版本浏览器是没问题的,但是在低版本浏览器是获取不到返回值的。

低版本IE;

高版本:

接受参数是不同的,所以会出现刚刚的问题,服务端需要按照这个类型来做兼容支持。这样既可实现 IE7+ 的图片上传功能。

增加登录验证支持

看似简单而合理的需求,实则坑道无限。问题,无论低版本或者高版本都是无法上传成功,都会被登录拦截器拦截。

原因:

  1. XHR 在 CORS 时,浏览器认为请求是不安全的,所以不会自动携带 cookie 信息。

  2. Flash 的请求不是在页面发送的,所以也无法携带 cookie 信息。

解决方法:
高版本浏览器:

需要前端后端一直修改来支持此需求,前端改动:

需要给 XHR 的 withCredentials 设置为 true ,并且服务器端也需要打开开关配置才可以正常的传递 cookie。文档描述: https://xhr.spec.whatwg.org/#the-withcredentials-attribute

代码如下:


1

2

3

4

5

6

7

8

9

10

11

var param = new FormData ();

param . append ( 'imgData' , file );

xhr = new XMLHttpRequest ();

/*新增进度条监听函数*/

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

xhr . addEventListener ( "load" , _self . uploadComplete , false );

xhr . addEventListener ( "error" , _self . uploadFailed , false );

xhr . addEventListener ( "abort" , _self . uploadCanceled , false );

xhr . open







请到「今天看啥」查看全文