场景描述
遇到这样一个开发场景,服务器A作为一个web server(可以看做master)而服务器B 作为一个运行长时间作业的jobs server(slaver),提供restful API 给服务器A调用,并且接受master的参数运行执行时间较长的脚本。由于脚本存储在slaver上面,且脚本的上传是在web 前端页面完成的,如何处理脚本的上传是一个值得思考的问题。首先想到的是一个非常常规的做法:将脚本首先暂存在master上面,然后在master server 上调用API再次将文件传递到slaver。这个过程过于复杂,其中还涉及到了两次的文件上传的过程,所以弃用。之前搞前端开发的时候做过跨站点资源的访问问题,正好在这个问题上web server 和 jobs server 属于不同的domain,可以尝试使用CORS资源访问的方式实现这个过程。
前端处理过程
首先纯粹的Jquery还没发实现form元素里面的文件上传,还需要一个jquery 的plugin jquery.form.js
然后最简单做法如下:
<form id="formid">
<input type="file" name="file"/>
<button type="submit" >submit</button>
</form>
$('#formid').ajaxForm({
'url':remoteapi // 由于是跨站点文件传输,所以这个地方的url必须要配置成远端server提供的接受文件的API
});
后端处理过程
web server 以及 jobs server 都是采用django开发完成,所以需要研究一下如何在django上面开启CORS功能,保证跨站点的请求能够正常的应答。django里面CORS的实现有三种方案。第一:jsonp 实现,大家都知道这种方式只能够处理get请求,所以直接忽略;第二,添加Access-Control-Allow ***
的各种响应头在response里面,这种方式也是常规的一种方式,至少使用任何一种语言开发后端的程序实现CORS资源访问都可以采用这样的一种方式;第三,使用django 的django-cors-headers
中间件,目前调研来看,在django框架里面,这种方式实现CORS资源访问是一个最佳的实践。
主要说明一下在django框架下方法二以及方法三如何实现CORS。
方法二实现步骤:
step1: view.py 文件中添加响应头,内容如下:
def do_request(request):
response = HttpResponse()
# 设置可以进行跨域访问的主机名,这个地方在简单请求时设置为任意主机可访问,但是在复杂请求,有OPTIONS预检请求时,必须设置与请求的域相同。
response['Access-Control-Allow-Origin'] = 'http://localhost:8000'
# 设置允许跨域访问的方法,一般是如下三个方法,OPTIONS方法比较重要,因为在较为复杂的跨域请求过程中OPTIONS请求会作为一个预检请求优先发送
response['Access-Control-Allow-Methods'] = 'POST,GET,OPTIONS'
# 设置CORS 的相关缓存,在这个时间内如果已经存在OPTIONS请求发送,那么复杂请求就不会每一次都预先发送一个OPTIONS请求,但是如果浏览器本身清除缓存,那么这个字段设置无效
response['Access-Control-Max-Age'] = 3600
# 响应首部,一般是在请求头中有Access-Contorl-Request-Headers 的时候在响应的头部中也需要设置。为了避免出错还是与浏览器端观察到的Access-Control-Request-Headers内容一致。
response['Access-Control-Allow-Headers'] = 'x-csrftoken'
通过如上的设置,可以成功实现跨域的文件传输。
方法三实现步骤:
step1:settings 文件中添加corsheaders
到INSTALLED_APPS
中。
step2:settings文件中添加orsheaders.middleware.CorsMiddleware 到MIDDLEWARE
的顶部。
step3: settings 文件中简单设置访问域的白名单,来自名单中的域的请求可以被正常处理。
CORS_ORIGIN_WHITELIST = (
'localhost:8000',
'127.0.0.1:8000'
)
然后就可以实现CORS文件传输了,当然上面使用django-cors-headers
中间件只是用到了最简单的配置选项,复杂的配置选项参考https://github.com/ottoyiu/django-cors-headers/
最后远端的接收文件并且存储在远端磁盘代码如下:
uploadfile = request.FILES.get('file',None)# file 与前端表征文件上传的元素的name一致。
if not uploadfile:
return HttpResponse('no file upload')
despath = os.path.join(DIR,uploadfile.name)
filewriter = open(despath,'wb')
for chunk in uploadfile.chunks():
filewriter.write(chunk)
filewriter.close()