`
宋双旺
  • 浏览: 155876 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解决使用FireFox下Flash上传文件时SESSION丢失的问题(swfupload)

阅读更多

解决使用FireFox下Flash上传文件时SESSION丢失的问题(swfupload)

 

这几天在项目中遇到的问题,稍微整理一下。

HTML 表单是我们常用来进行浏览器与服务器数据交互的途径,除了传递普通的文本数据,通过 type="file"的 input 控件,我们还可以向服务器发送文件。但在目前的实际使用中,基于 HTML 表单的文件选择框有着下面两个不尽人意之处:

  1. 一次只能选择一个文件
  2. 上传过程中,不能获取文件上传的进度

对于文件选择的数量,事实上在 HTML4.01 规范 中对文件选择框的描述虽然没有明确提出可以同时选择多个文件,但从其用词可以看出,文件选择控件事实上是应该支持同时选择多个文件的:

This control type allows the user to select files so that their contents may be submitted with a form. The INPUT element is used to create a file select control.

可以看见,“文件”一词使用的是复数形式。同时,RFC 1867: Form-based File Upload in HTML  的 3.3 节中,也有这样的描述:

If multiple files are selected, they should be transferred together using the multipart/mixed format.

说明文件选择框应当能够处理同时选择多个文件的情况。但需要注意的是,这个描述出现在这篇规范文档的 3. Suggested implementation 章节中,仅仅是建议的实现方式,所以除了以前有几个版本的 Opera  曾经支持过多文件选择,其余浏览器都仅仅实现了单个文件的选择功能。

为了解决这个问题,HTML5 中进行了明确 ,带有 multiple 属性的 input 控件将可以有多个取值,自然也包括文件选择框。但这不是今天说的重点,目前的困境还是摆在我们眼前的。

对于文件上传的进度,就更不好办了:一是文件上传本身就无法使用 AJAX 来进行页内无刷新上传,需要使用隐藏 iframe 来实现。而获取上传进度还得依靠 AJAX 向服务器端发送请求来获取,利用的手段可以是 AJAX 轮询、iframe + htmlfile 甚至是 WebSocket,但本质上做的事情都有违常理:浏览器自己发送了多少内容,却需要一遍遍地请求服务器来进行告知。其次,由于文件上传和进度查询采用的 是不同的数据通道,还得使用额外数据来维护两者之间的联系,显得非常繁复。

好了,说了那么一大段就是为了引出目前使用 Flash 来进行文件上传的原因。目前我们项目采用的是SWFUpload  这个 Flash 文件上传工具,支持文件批量选择,并且可以方便地进行上传进度的查询。但是在我们的项目的之前版本中,当页面需要使用 session 中的用户信息时,却无法在 Firefox 下使用它进行正常的文件上传。

在 IE 下,上传工具能够工作,而一到 Firefox 下,SWFUpload 就会提示错误 302。通过从 Fiddler 抓包,发现上传文件的请求被 302 重定向到了登陆页面,所以无法正常上传文件。也就是说,之前用户登陆后的 session 信息在 Flash 发送的上传请求中丢失了。再一看请求的 header,当中没有可以用来标识当前 session ID 的 cookie 值(对于 J2EE 为 JSESSIONID,PHP 为 PHPSESSID 等)。这是什么原因呢?经过一番搜索,找到了 Adobe 官方的一篇文章 ,说道:

A FileReference.upload() currently does not use the same cookies as your browser session if you are using Firefox (on Windows). In such cases, cookie information has to be inserted manually.

好吧,这个解释虽然很清楚地表明,Flash 在 Firefox 下进行文件上传不会使用浏览器 cookie 中的 session ID,但是貌似并没有回答文章标题当中的“为什么”,即为什么不使用和浏览器中的 session ID 来进行通信。

看来 cookie 是指望不上了,那只能像上面说的那样“手工”传递 session ID 了。于是我们可以在 URL 中拼接一个如 ";jsessionid=blahblah" 的字符串(注意要拼在路径之后,参数之前),像下面这样:

http://example.com/app;jsessionid=blahblah?q=blah

Servlet 规范  7.1.3 节中的规定,当客户端不接受 cookie 时,Servlet 容器应当能解析出这类 URL 中的 JSESSIONID,来维持当前 session 的状态。其他服务器端环境中也有类似的机制。于是我们对文件上传功能做了一定的修改:在用户进入上传页面时,就把当前的 session ID 写到页面中,作为 JavaScript 变量拼接到 SWFUpload 上传文件的目标 URL 中,Flash 就可以利用我们人工传入的 JSESSIONID 来维持登陆状态了。当开始上传时,Flash 通过自己的连接通道向服务器发送数据,但是因为请求的路径中包含了 session 信息所以可以和浏览器的 session 状态保持同步,服务器可以通过 URL 中的 session ID 来获取用户登录的信息。

于是,302 错误被解决了,看起来一切都 OK 了。可是,不久我们又发现了新的问题:当用户打开上传页面后较长时间没有操作,服务器端的 session 超时了,这个时候进行文件的上传用的还是超时的那个 session ID,所以会失败也是应该的。但是当这个时候用户重新进行了登录,再次进入上传页面上传,却仍然会失败,只有重新启动浏览器才能再次进行上传。这是为什么 呢?从服务器端错误来看,还是用户的登陆信息丢失的问题,也就是说,Flash 在上传文件时,还是没能将用户进行过登陆的这个 session ID 成功传递给服务器端。通过在 Fiddler 中抓包分析,终于找到了原因。下面几张示意图大致描述了这个问题产生的过程:
登 陆后 Flash 第一次进行上传时,自身没有 JSESSIONID 这个 Cookie,所以使用手工拼接到请求 URL 中的浏览器 JSESSIONID 即 XXX 进行提交,服务器解析出了 JSESSIONID 并且在内存中找到了其对应的 session 信息,成功进行了身份验证,最后返回上传成功的信息。

然 而当 XXX 这个 session ID 超时以后,Flash 仍然以刚才重写过的 URL 发送请求(图中[1]),服务器解析出 JSESSIONID 后发现已经没有 XXX 这个 session 了,于是重新创建了一个 ID 为 YYY 的 session(图中[2]),并且在返回的响应中除了登陆失败的信息外还加入了 SET-COOKIE:JSESSIONID=YYY 的请求头(图中[3])。于是这时在 Flash 的 LSO (“Flash cookies”) 中却把这个不带用户登录信息的 session ID 保存了下来。

发 现登陆超时后,用户重新登陆,在新的 ID 为 ZZZ 的 session 中留下了有效的登录信息,进入上传页面后,生成了新的拼接 JSESSIONID 的 URL 传递给 Flash 控件,此时进行上传时, Flash 发送的请求既包含了 URL 中的 JSESSIONID,也带了 Cookie 请求头中的 JSESSIONID(图中[1])。按 Servlet 规范,当请求有 Cookie 头中的 JSESSIONID 时,URL 中的就被忽略了,于是服务端判断此请求应该在 YYY 这个 session 中进行处理(图中[2]),于是导致了用户看似已登录,Flash 请求却使用了另一未登录的 session 导致上传失败。

所以,要让 Flash 能够正确使用 URL 中指定的 session,就必须防止 flash cookies 中记录 JSESSIONID 值。如果 Set-cookie 头是 Web 服务器或 Servlet 容器自动加上的,那就需要我们在 Web 应用中将对应的 Cookie 值删除。下面以 Java 代码为例,我们可以通过添加一个名称同样为 JSESSIONID 的立即失效(通过设置 Max-Age=0,参见RFC 2109: HTTP State Management Mechanism  的 4.3.3 节)的 Cookie 来覆盖之前的值:

Java代码:

Cookie cookie =new Cookie("JSESSIONID", "");
cookie.setMaxAge(0);
response.addCookie(cookie);

这样在 session 超时时,上传文件失败返回的请求中会带这样的头:

Set-cookie:JSESSIONID=YYY;
Set-cookie:JSESSIONID="";Max-Age=0

于是在 flash cookie 中 YYY 这个 JSESSIONID 刚刚被设置就被清除了,在重新登陆后 Flash 发送的请求就不会带有 Cookie 头,不会覆盖 URL 中设置的值了。

总结一下,虽然这个过程说起来挺复杂,但解决方法还是比较简单明了的:

  1. 在上传文件的目标 URL 中显式传递 session ID;
  2. 在处理上传的应用代码中,当发现无登录信息的 session ID 时,不发送 Set-cookie 头或在应用代码中将其用一个立即失效的同名 cookie 覆盖。

    其他资料: 
    ActiveX模式下的Flash插件使用的是IE的链接池,所以获取的Session是一致的,而在
    Firefox下的是Plugin模式,使用自有的链接,没有使用FF的链接池,所以产生了两个
    不同的链接,所以Session找不到了,不过也不是没有解决办法,可以通过页面将 
    SessionID传给Flash,Flash在上传访问后台程序,如PHP时,将SessionID传给PHP,
    PHP可通过此SessionID找到相应的Session
分享到:
评论
1 楼 sky_kk 2016-06-28  
很好  

相关推荐

    swfupload flash上传兼容所有浏览器

    由于Flash的广泛安装基础,这种方法可以在大多数现代计算机上运行,从而解决了IE、Firefox、Chrome、Safari等不同浏览器间的上传兼容性问题。 以下是关于SWFUpload的一些关键知识点: 1. **初始化设置**:...

    swfupload控件实现flash文件上传

    11. **修复已知bug**:包括IE中的刷新问题,Firefox的滚动条问题,以及一些竞态条件和缓存问题。 12. **ASP.Net Forms兼容**:确保在ASP.Net环境中也能正常工作。 SWFUpload的设计理念是将用户界面的控制权交给...

    swfupload asp版 asp上传大文件,批里上传

    在ASP环境中,SWFUpload 可以很好地解决传统ASP上传文件时遇到的大小限制和性能问题。 首先,我们要理解SWFUpload的工作原理。它利用了Adobe Flash技术来绕过浏览器对文件上传大小的限制,因为Flash插件允许上传更...

    文件上传插件SWFUpload的使用指南

    SWFUpload是一个强大的文件上传插件,它结合了Flash和JavaScript技术,提供了一种无刷新的文件上传体验。虽然SWFUpload已经不再更新,并且官方文档可能无法访问,但了解其工作原理和使用方法仍然对某些场景有帮助,...

    swfupload文件上传下载

    SWFUpload是一个开源的Flash组件,它允许网页在不依赖浏览器特定控件(如IE的ActiveX或Firefox的NPAPI插件)的情况下实现文件的上传功能。这个技术结合了Flash的广泛兼容性和JavaScript的灵活性,使得文件上传在多种...

    swfupload多文件上传组件

    o 在FireFox中,如果窗口的滚动条没有回滚到顶部,那么Flash无法加载 o Race-conditions when files are cached * 兼容ASP.Net Forms SWFUpload v2 延续了SWFUpload的设计目标,将UI分离以交给开发人员控制和...

    swfupload文件上传控件

    它利用Flash技术,提供了多文件上传和进度显示的功能,使得用户在上传大文件或多个文件时能够有更好的交互体验。 ## 一、SWFUpload 简介 SWFUpload 是一个开源的JavaScript库,通过在HTML页面中嵌入Flash对象来...

    swfupload(jsp+flash文件上传)

    SwfUpload 是一款开源的文件上传组件,它结合了Java Server Pages (JSP) 和Adobe Flash技术,提供了一种在Web应用中实现高效、用户体验友好的文件上传方式。这款组件在早期的Web开发中非常流行,因为它允许用户通过...

    swfupload多文件上传带进度条实例

    在这个实例中,我们将探讨如何在VS2012环境下,使用.NET Framework 4.0开发一个基于SWFUpload的多文件上传功能。 首先,让我们理解SWFUpload的工作原理。SWFUpload是基于Flash技术的,它创建了一个隐藏的Flash对象...

    SwfUpload 多文件上传

    SwfUpload 是一款开源的Flash上传组件,它允许用户在网页上实现多文件上传功能,尤其适用于需要大文件上传或批量上传的场景。这个技术在Web开发中被广泛应用,因为它可以提供比传统HTML表单上传更好的用户体验。...

    step-by-step多文件WEB批量上传(swfupload)的完美解决方案的相关

    在Web开发中,批量上传功能是一项常见的需求,尤其在处理大量图片、文档或者其他类型文件时。SWFUpload是一个流行的JavaScript库,它允许用户通过Flash插件实现多文件的批量上传,提供了一种友好的用户体验。本解决...

    大名鼎鼎SWFUpload- Flash+JS 上传

    SWFUpload使用一个隐藏的Flash影片来控制文件的选择和上传。JavaScript用来激活文件选择对话框。 此文件选择对话框是可以设置允许用户选择一个单独的文件或者是多个文件。 选择的的文件类型也是可以被限制的,因此...

    SwfUpload多文件上传

    将SwfUpload集成到Struts1中,可以提供一个高级的文件上传体验,让用户在上传大量文件时不再需要逐一操作。 在SwfUpload的实现过程中,主要涉及以下几个关键知识点: 1. **Flash技术**:SwfUpload基于Flash插件...

    SWFUpload多个超大文件上传

    SWFUpload通过切割大文件为较小的块来解决这个问题,这些小块可以逐个上传,然后在服务器端进行重组。 首先,我们需要在网页中集成SWFUpload库。这通常涉及到在HTML页面中嵌入SWFUpload的JavaScript和Flash组件。...

    flash javascript 异步上传文件 --swfupload

    SWFUpload是一个开源的JavaScript库,它结合了Adobe Flash技术,允许用户在不刷新整个页面的情况下进行多文件的异步上传。这种方法解决了传统HTML表单上传的局限性,提供了更好的用户体验。 首先,我们要理解...

    SWFUpload 异步文件上传

    当文件上传过程中出现问题时,如网络中断或文件格式错误,SWFUpload 提供了相应的错误处理机制,可以帮助开发者更好地控制和反馈错误信息。 10. **回调函数** SWFUpload 提供丰富的回调函数,如onFileQueued、...

    swfupload flash插件上传

    **标题:“SwfUpload 闪存插件...总之,SwfUpload 是一个强大的文件上传解决方案,通过JavaScript和Flash的结合,为Web应用提供了高效、友好的文件上传体验。它的源码开放,可定制性强,适合各种类型的Web开发项目。

    文件上传利器SWFUpload使用指南

    SWFUpload 是一款强大的文件上传插件,它利用 Flash 技术实现无刷新的文件上传功能,同时提供了自定义 Flash 按钮样式的能力。在网页中,SWFUpload 主要由三个部分组成:SWFUpload.js(JavaScript 文件)、swfupload...

    最新swfupload文件上传

    它巧妙地结合了Flash技术和JavaScript,为用户提供了一种高效、用户友好的多文件上传解决方案。在本文中,我们将深入探讨SWFUpload的工作原理、特点以及如何在实际项目中进行集成。 一、SWFUpload简介 SWFUpload 是...

    SwfUpload(文件批量上传,完美运行,注释丰富)

    SwfUpload 是一款开源的...总的来说,SwfUpload是一个强大且灵活的文件上传解决方案,尤其适用于需要大量处理用户上传文件的网站或应用。其完整的注释和易用性使得它成为开发者们实现批量上传功能的首选工具。

Global site tag (gtag.js) - Google Analytics