1. 程式人生 > >Jquery+Django 實現 CORS 檔案傳輸

Jquery+Django 實現 CORS 檔案傳輸

場景描述

遇到這樣一個開發場景,伺服器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 檔案中新增corsheadersINSTALLED_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()