關於這個跨域上傳圖片的問題,其實去年底的時候就該去實現的,因為老板朝三暮四,一會兒讓做這個,一會兒看那個,就耽誤了。因為這個過程花費了我整整一天的時間,我認為有必要記錄下來。
首先,項目是一個ERP,針對的是公司的一個小型電商的網站。項目經理讓我搭建一個圖片服務器, 當時也是為了完(嘗)成(嘗)任(新)務(鮮),用的都是當時從沒接觸過的。通過百度就選擇了 Nginx + Nodejs + express + ImageMagick 來實現的。 當時還簡單看了一下淘寶的TFS(Taobao FileSystem)太高大上了,因為預估網站圖片不會非常多,就用系統自帶的文件系統。 Nodejs也是邊學邊寫,可是調試express 這種MVC的時候,就不管用了。。。試了很久也不行。。。 就采用邊看api 邊打印出來調試。總算可以上傳,下載瀏覽圖片了。
后來移至到項目中才發現,跨域是個很大的問題。圖片服務器,提供一個接口。當時想了兩套解決方案:
- 先上傳到項目中,然后再編寫一個windows服務,來定時把上傳的圖片傳到圖片服務器中;
- 在圖片服務器上寫一個頁面,然后通過iframe嵌套在項目中。
第二個解決方案直接被項目經理否決了,我也覺得寫那么多東西不太好,也不想寫這么多東西,只想一步到位。然后就花了一天的時間,查資料,實驗。 當時可選的上傳的控件有三個,原先項目里面的ajaxSubmit,領導推薦的plupload,我自己查到百度的webupload。 最后我當然選擇使用我自己查到的了。 根據官方給出的api,demo來嘗試寫。 看到demo里面寫的是server地址是以http開頭的,不是項目中的相對路徑。就以為是天然可以跨域,后來找到github上面issues里面,提到這個沒有采用jquery file upload 的form post的形式,但是不采用這個可以實現文件修改的,也就實現上傳前壓縮,和分塊上傳這些功能的。
然后為了跨域我做了這些嘗試:
- 修改nginx的代理,失敗。
- 修改nodejs的express里app.js,在response的消息頭部加上下面這段代碼, 失敗。

- 后來我想,只需要在條用上傳的方法的頭部加上,后來使用chrome插件postman,模擬調用,發現POST可以接受到,POST跨域成功。
- 后來發現WebUpload,會先發送一個OPTIONS的請求,百度了一下才發現,HTTP協議不止POST和GET。。
瀏覽器在跨域請求前會發個options請求來驗證是否跨域,所以后端再處理這個options請求時,要告訴瀏覽器一些信息。其實就是個header信息。
HTTP請求方法並不是只有GET和POST,只是最常用的。據RFC2616標准(現行的HTTP/1.1)得知,通常有以下8種方法:OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT。 OPTIONS方法是用於請求獲得由Request-URI標識的資源在請求/響應的通信過程中可以使用的功能選項。通過這個方法,客戶端可以在采取具體資源請求之前,決定對該資源采取何種必要措施,或者了解服務器的性能。
OPTIONS請求方法的主要用途有兩個:
1、獲取服務器支持的HTTP請求方法;也是黑客經常使用的方法。
2、用來檢查服務器的性能。例如:AJAX進行跨域請求時的預檢,需要向另外一個域名的資源發送一個HTTP OPTIONS請求頭,用以判斷實際發送的請求是否安全。
- 發現Webupload發送的OPTIONS請求,雖然阻止,但是,返回的狀態碼是200,也就是說Nginx是配置正確的,趕緊將Nginx配置改回來。
- 后來靈光一閃,想起Express的路由好像會控制,接收什么協議的訪問。然后趕緊嘗試看看,成功了很是興奮。
var router=express.Router(); var file_ctrl = require('../controller/filectrl') /**上傳文件*/ router.options('/upload',file_ctrl.upload); router.post('/upload',file_ctrl.upload);
最后再放兩張圖,成功和失敗 返回的Response Headers信息,確實不同。 基於這個,那不是所有的跨域問題都可以解決了,像網上說的Jsonp,iframe 完全都可以不用了。嘿嘿


