引言
記得以前剛開始學習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/document_detail/31924.html
https://gosspublic.alicdn.com/AliyunJavaSDK/3.10.2/javadoc/index.html?spm=a2c4g.11186623.0.0.14c240c20nrAKm