文档章节

Flask: 跨域上传的回调方案

陈亦
 陈亦
发布于 2014/02/15 19:15
字数 1777
阅读 1950
收藏 35

随着互联网业务的规模不断扩大,网站的开发方式也产生发巨大的变化。就拿上传来说,早些年通常都是网站自身包含上传模块,通过跳转方式或iframe方式进行上传。这没有涉及到跨域,所以对于上传结果的通知是很容易做到的。然而现在越来越多的做法是将上传功能分离开来,形成独立的上传域来提供上传服务。本文主要是针对跨域上传的上传结果通知分析并提供解决方案。

跨域上传的方式

  1. 使用第三方存储,如七牛云存储

  2. 重定向上传方式

  3. iframe上传方式

使用第三方存储

比如使用七牛云存储,这种方式第三方一般会提供各个语言的SDK,如果正巧您所使用的语言没有相应的SDK,那就只能自己去实现了。实现起来倒也不难,无非就是实现第三方授权的流程,然后通过文件上传协议提交文件到第三方。这种方式一般是通过服务器端来完成的,上传完成后第三方会有个上传反馈,然后返回到前端。

重定向上传方式

这是最传统的上传方式。各种上传方案都可以很容易的实现它。将上传表单重定向到上传网址,完成上传后可携带参数跳转回来。

iframe上传方式

这种方式是在页面中嵌入一个隐藏的iframe,上传表单提交到iframe来完成上传。现代浏览器都比较好的支持了iframe,所以这个方式也是通用的。这也是本文将讨论的上传方案。

iframe上传完成如何通知

同域或子域方式

如果是同域方式,因为iframe是嵌入在网页中,所以可以在iframe上传完成后通过parent来调用父框架提供的方法并将参数传入来实现通知,或者可以在上传完成后父框架获取iframe的引用并得到iframe的输出内容来实现通知。而如果是子域的方式,则还需要设置document.domain为子域。

跨域方式

因为是跨域方式,这将导致上传完成后目标iframe没有权限去调用父框架中的方法,并且父框架也没有权限去访问子框架的内容,所以无法进行通知上传结果。

是的,一般来说,在iframe上传完成后都会输出数据或一段js代码。但是如果输出的是一个iframe呢?本文将用2个host来演示这种情况。www.aw.com 是需要上传的网站,www.file.com 是提供上传的网站。我们来看个图:

上图很清晰的体现了这种包含关系。A上传到B,B上传完成后输出iframe,并指向A域名的一个页面,也就是上图中的C。A和C是同域的,即使是A不能访问C,但是C却可以通过parent.parent来访问A。为了演示,我配置了以下host:

aw目录结构如下:

www/aw

----app.py

----templates

--------index.html

--------cross.html

app.py源码:

#coding: utf8
import os
from datetime import timedelta
from flask import Flask, render_template
import urllib

app = Flask(__name__)

app.secret_key = os.urandom(24)
app.permanent_session_lifetime = timedelta(seconds=24 * 60 * 60)

@app.route('/')
def index():
    return render_template('index.html', **dict(upload_url='http://www.file.com:6667/upload'))

@app.route('/cross.html')
def cross():
	return render_template('cross.html')

if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("6666"),
        debug=True
    )

index.html源码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>aw</title>
    <meta name="author" content="" />
    <meta http-equiv="X-UA-Compatible" content="IE=7" />
    <meta name="keywords" content="aw" />
    <meta name="description" content="aw" />
    <script type="text/javascript" src="http://cdn.staticfile.org/jquery/2.1.0/jquery.min.js"></script>
</head>
<body>
<form enctype="multipart/form-data" action="{{ upload_url }}" method="POST" target="upload_iframe">
    <input name="UploadName" type="file" />
    <input type="submit" value="上传" />
</form>
<iframe id="upload_iframe" name="upload_iframe" width="0" height="0" style="display: none;"></iframe>
<script type="text/javascript">
// 上传完成回调
function uploadComplete(data)
{
	console.log('上传完成:' + data);
}
</script>
</body>
</html>

cross.html源码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>aw cross</title>
    <meta name="author" content="" />
    <meta http-equiv="X-UA-Compatible" content="IE=7" />
    <meta name="keywords" content="aw cross" />
    <meta name="description" content="aw cross" />
    <script type="text/javascript" src="http://cdn.staticfile.org/jquery/2.1.0/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(function() {
	var href = location.href;
	var index = href.indexOf('?');
	if (index < 0)
	{
		var data = 'result=upload_error';
	}
	else
	{
		var data = href.substring(index + 1);
	}
	// 将数据通过调用parent.parent.uploadComplete方法来传递
	parent.parent.uploadComplete(data);
});
</script>
</body>
</html>

file目录结构如下:

www/file

----app.py

app.py源码:

#coding: utf8
import os
from datetime import timedelta
from flask import Flask, request, render_template
import urllib

app = Flask(__name__)

app.secret_key = os.urandom(24)
app.permanent_session_lifetime = timedelta(seconds=24 * 60 * 60)

@app.route('/upload', methods=['POST'])
def index():
	'''忽略上传文件处理细节,直接返回数据'''
	cross_html = 'http://www.aw.com:6666/cross.html?result=upload_complete'
	return '<iframe width="0" height="0" style="display:none;" src="%s"></iframe>' % cross_html

if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("6667"),
        debug=True
    )

这样就实现了跨域回调,知道了原理其实就不难了,如有需要可进行封装,如实现跨域检测,如果是同域则使用同域的方式进行回调,如果是跨域,则使用跨域的方式进行回调。并且可实现多文件上传方案。

关于超时

上传超时是必须处理的上传错误之一。对于iframe上传(这里并没有特指同域或跨域)来说,超时机制将会限制整个上传所占用的时间,这是有必要的,否则如果网络异常,前端将一直显示正在上传中,这是极不友好的用户体验。另一方面也是为了安全考虑。

其实实现iframe的上传超时机制非常简单。通过setTimeout在固定时间后去remove iframe,当然如果上传是成功的则会提前clearTimeout。所以如果setTimeout成功执行则肯定是超时了,否则就是上传完成(至于是上传成功或上传失败则由服务器端返回的状态码来确定)。比如:

index.html源码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>aw</title>
    <meta name="author" content="" />
    <meta http-equiv="X-UA-Compatible" content="IE=7" />
    <meta name="keywords" content="aw" />
    <meta name="description" content="aw" />
    <script type="text/javascript" src="http://cdn.staticfile.org/jquery/2.1.0/jquery.min.js"></script>
</head>
<body>
<form enctype="multipart/form-data" action="{{ upload_url }}" method="POST" target="upload_iframe">
    <input name="UploadName" type="file" />
    <input type="submit" value="上传" />
</form>
<iframe id="upload_iframe" name="upload_iframe" width="0" height="0" style="display: none;"></iframe>
<script type="text/javascript">
// 上传完成回调
function uploadComplete(data)
{
	timeout_id && clearTimeout(timeout_id);
	console.log('上传完成:' + data);
}
var timeout_id = setTimeout(function() {
	$("#upload_iframe").remove();
	uploadComplete("上传超时")
}, 10000);
</script>
</body>
</html>

大致上就是这样,这是很常用的跨域上传方案,有必要认真理解并加以实践。

© 著作权归作者所有

陈亦
粉丝 241
博文 23
码字总数 53194
作品 0
浦东
高级程序员
私信 提问
试图做前后端分离项目遇到的困难

先分享两个前后端分离的技术文章。 Web应用的组件化开发 http://blog.xufei.gitpress.org/~posts/2013-11-20-Web%E5%BA%94%E7%94%A8%E7%9A%84%E7%BB%84%E4%BB%B6%E5%8C%96%E5%BC%80%E5%8F%91......

change_solider
2014/07/29
2.9K
7
layui文件上传upload跨域回调问题解决方案

最近在开发一个项目,项目是由api接口端和页面展现端组成的,也就是api接口和页面是不同子域名。如:api.abc.com和admin.abc.com。 在使用layui的upload组件时遇到了跨域问题,上layui的git...

宇润
2017/04/08
1K
1
AJAX跨域调用相关知识-CORS和JSONP(引)

AJAX跨域调用相关知识-CORS和JSONP 1、什么是跨域 跨域问题产生的原因,是由于浏览器的安全机制,JS只能访问与所在页面同一个域(相同协议、域名、端口)的内容。 但是我们项目开发过程中,经...

辉煌霸猪
06/26
40
0
(转载学习)XMLHttpRequest Level 2 使用指南

本文为转载学习 原作者:阮一峰 原文链接:http://www.ruanyifeng.com/blog/2012/09/xmlhttprequestlevel2.html 一、老版本的XMLHttpRequest对象 在介绍新版本之前,我们先回顾一下老版本的用...

heroShane
2014/01/24
36
0
最新的jsp版本的ueditor跨域上传图片,回调函数失败怎样解决

公司最近想用ueditor实现跨域上传图片,即WEB端和服务端分别部署一套ueditor,想从WEB端直接上传图片到服务端,并且WEB端要能正常回显图片。现在的问题是,我从WEB端把图片成功上传到服务端了...

在京奋斗者
2017/03/05
607
0

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
今天
13
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
今天
7
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
今天
9
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
今天
12
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部