引言
記得以前剛開始學習web專案的時候,經常涉及到需要上傳圖片啥的,那時候都是把圖片上傳到當前專案資料夾下面,每次專案一重啟圖片就丟了。雖然可以通過修改/tomcat/conf/server.xml
配置檔案,配置一個上傳圖片的本地資料夾,即配置一個工程配置虛擬路徑,這樣可以避免專案重啟圖片丟失。自從參加工作以來基本就沒有遇到使用這種方式來儲存圖片了。一般要麼自己搭建檔案伺服器,要麼使用付費的檔案服務。比如七牛雲、阿里雲、騰訊雲等。今天我們就一起來聊聊如何使用阿里雲OSS
檔案上傳。
oss 檔案上傳
使用OSS檔案上傳,阿里雲提供瞭如下幾種方式,大家可以選擇適合自己的方式。
Web端上傳
Web端常見的上傳方法是使用者在瀏覽器或App端上傳檔案到應用伺服器,應用伺服器再把檔案上傳到OSS。具體流程如下圖所示。
這種方式肯定不可取它有如下去缺點:
- 上傳慢:使用者資料需先上傳到應用伺服器,之後再上傳到OSS,網路傳輸時間比直傳到OSS多一倍。如果使用者資料不通過應用伺服器中轉,而是直傳到OSS,速度將大大提升。而且OSS採用BGP頻寬,能保證各地各運營商之間的傳輸速度。
- 擴充套件性差:如果後續使用者數量逐漸增加,則應用伺服器會成為瓶頸。本來就已經採用了OSS上傳了,然後還要在佔用自己伺服器。
費用高:需要準備多臺應用伺服器。由於OSS上行流量是免費的,如果資料直傳到OSS,將節省多臺應用伺服器的費用。
JavaScript客戶端簽名直傳
這種方式採用純前端直接上傳,不經過應用伺服器,不過這種方式阿里雲給到的一些關於OSS上傳的一些核心引數(AccesssKey ID和AccessKey Secret相當於我們在阿里雲那邊申請的賬號和密碼)也需要寫在前端程式碼裡面,這樣就容易導致我們核心引數被洩漏。存在安全隱患。這種方式也不推薦。
服務端簽名後直傳
前面直接在前端簽名上傳會有安全隱患,存在引數洩漏。我們可以把引數放在服務端,然服務端和阿里雲去互動,這樣就不存在核心引數的洩漏。
如何接入
引入依賴
因為本人是從事java開發的,所以直接引入官方提供最新的maven依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun.oss/aliyun-sdk-oss --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.14.0</version> </dependency>
為什麼要引入最新的依賴。因為如果遇到什麼問題需要找阿里雲的人幫忙解決的時候,別人大多數都會問你什麼版本的sdk,然後如果遇到那種一時半會比較難解決的問題,人家會推薦你升級最新版本試試。因為可能在最新版本修復了你所遇到的bug。有人可能會說,引入最新版本不就是幫別人踩坑嗎?萬一解決一個bug又引入兩個bug列?這種情況也不是沒有可能的。
服務端構建簽名
上圖是官網提供的入門例子,程式碼是一大坨,我們可以看看稍微優化後的程式碼:
建立一個單例的ossClient
,可以複用執行緒,不需要每次都去new ossClient()
.String host = String.format("https://%s.%s", ossPropertoooies.getBucketName(), ossPropertoooies.getEndpoint()); long expiredTime = System.currentTimeMillis() + fileOssProperties.getUploadSignatureTtl(); Date expiration = new Date(expiredTime); // 根據檔名和檔案型別設定儲存路徑,可以按照檔案型別+日期格式+UUID檔名 進行分割 String filepath = getFilePath(request.getCategory(), request.getFilename()); PolicyConditions policyConditions = new PolicyConditions(); policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, fileOssProperties.getUploadSizeLimit()); policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, filepath); String postPolicy = ossClient.generatePostPolicy(expiration, policyConditions); byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8); String encodedPolicy = BinaryUtil.toBase64String(binaryData); String postSignature = ossClient.calculatePostSignature(postPolicy); SignatureDTO signature = new SignatureDTO(); signature.setAccessId(ossPropertoooies.getAccessKeyId()); signature.setPolicy(encodedPolicy); signature.setSignature(postSignature); signature.setFilepath(filepath); signature.setHost(host); signature.setExpire(fileOssProperties.getUploadSignatureTtl() / 1000); signature.setReqFilename(request.getFilename());
接入起來還是非常簡單的,一個後端簽名,前端上傳前後分離的檔案上傳就已經完成了。這裡我們使用
postman
模擬下前端上傳,當然這裡可以改為前端使用ajax
,或者其他方式都可以。上傳的url是由我們自己申請的bucketname
和endpoint
組成的
但是其實這裡面也是有許多坑的我們還是需要稍微注意下。頻寬限制
上傳和下載都會有頻寬的限制,如果我們是採用外網直傳到阿里雲oss的話,需要注意下我們的外網頻寬是否夠用,以及應對大檔案的上傳是不是會把頻寬打滿。如果頻寬被打滿我們上傳就gg了。同樣的下載也有頻寬限制的,需要避免大檔案的下載,如果遇到這種大檔案下載我們可以採用其他的方式,比如使用oss的客戶端。所以我們需要合理的考慮我們伺服器的頻寬。如果我們的應用直接是部署在阿里雲上面的話,我們可以採用內網的上傳和下載。這樣的話就不會有頻寬的限制。
API使用需要注意點
當我們使用
OSSclient
提供的一些api
使用的時候需要仔細去看看裡面是怎麼實現的,或者看看它的文件有沒有特殊交代的。
比如使用OSSclient
提供的processObject
方法我們最後需要關閉輸入流,如果流不關閉,連結不被釋放。應用連結馬上就會被佔滿,然後服務就會成為一個假死的狀態,這個問題我們在生產環境就遇到一次。如下圖所示執行緒一直沒有被釋放。
像這種為什麼需要我們手動去關閉流,為什麼不直接api
幫我們關閉,阿里雲的回覆是因為這裡返回的流可能業務方自己需要複製、或者讀什麼的。所以需要呼叫方主動關閉下,在這個很隱祕的文件中我們也有找到這個答案。結束
- 由於自己才疏學淺,難免會有紕漏,假如你發現了錯誤的地方,還望留言給我指出來,我會對其加以修正。
- 如果你覺得文章還不錯,你的轉發、分享、讚賞、點贊、留言就是對我最大的鼓勵。
- 感謝您的閱讀,十分歡迎並感謝您的關注。
站在巨人的肩膀上摘蘋果:
https://help.aliyun.com/docum...
https://gosspublic.alicdn.com...