解決的問題:當前端並發上傳大量文件至伺服器時,伺服器帶寬存在瓶頸,會影響上傳速度
解決方案:使用STS臨時訪問憑證訪問OSS
流程:
根據不同項目使用情況,向公司OSS管理員(楊坤)提供bucket信息,申請許可權。具體包含以下內容:
前端在發起文件上傳請求前,判斷是否接近過期時間或已超過過期時間,並及時刷新臨時訪問憑證。
② iOS 關於OSS上傳文件
1.安裝OSS這些就不需要再說了,其次先讓後台配置好一些參數,然後拿到後便可以直接使用了
目前用到的主要參數有以下三個:
ServerUrl
Endpoint
bucketName
2.直接在封裝好的請求文件 CCNetworkRequstionMD5.m 裡面,增加一個方法 ( 多種文件類型上傳,傳入你所需要的文件數組即可)
3.以下是在作業上傳 .m 文件中的使用
在了解這方面的知識,找到了這一篇,借鑒了一下
https://blog.csdn.net/qq_33560608/article/details/88761764
③ oss上傳速度跟伺服器有關系嗎
以下代碼蔽塵使用分片上傳的方式,可有效解決,OSS文件上傳緩慢問題,但如果伺服器的寬頻過低還是會影響上傳速度,可將伺服器寬頻提高,以提升速度
1.引入POM
<!--阿里雲OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.9.1</version>
</dependency>
1
2
3
4
5
6
7
1
2
3
4
5
6
7
2.編寫文件上傳工具類
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 文件上傳工具類
*/
public class FilesUploadUtil {
/**
* 獲取上傳結果
* @param newFile 上傳文件
* @param folder 父級文件夾名稱
* @return 文件訪問路徑
*/
public static JSONObject obtainTheFileUploadResult(MultipartFile newFile, String folder){
JSONObject result=new JSONObject();
JSONObject data=new JSONObject();
long startTime = System.currentTimeMillis();
try {
// MultipartFile 轉 File
File file=multipartFileToFile(newFile);
//上傳文件
String[] resultArr = uploadObject2OSS(file, folder);
if (resultArr != null) {
String path = resultArr[1];
//絕對路徑,拼顫迅接CND加速域名,或自己的域名
data.put("src", "自己的公網IP".concat("/").concat(path));
//相對路徑
data.put("relativePath", path);
result.put("msg", 1);
result.put("errorMessage", null);
}
// 刪除本地臨時文件
deleteTempFile(file);
} catch (RuntimeException e) {
e.printStackTrace();
result.put("msg", 0);
result.put("errorMessage", "文件大小不能超茄並此過9.7G");
data.put("src", null);
data.put("relativePath", null);
}catch (Exception e) {
result.put("msg", 0);
result.put("errorMessage", "上傳錯誤:"+e.getMessage());
data.put("src", null);
data.put("relativePath", null);
}
result.put("data",data);
long endTime = System.currentTimeMillis();
System.out.println("------文件上傳成功,耗時" + ((endTime - startTime) / 1000) + "s------");
return result;
}
/**
* 上傳圖片至OSS 文件流
*
* @param file 上傳文件(文件全路徑如:D:\\image\\cake.jpg)
* @param folder 阿里雲API的文件夾名稱(父文件夾)
* @return String 返回的唯一MD5數字簽名
*/
public static String[] uploadObject2OSS(File file,String folder) throws Exception{
//獲取OSS客戶端對象
OSS ossClient=getOSSClient();
//OOS 桶名稱 bucketName
String bucketName="自己阿里雲的bucketName";
// 阿里OSS
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
Date date = new Date();
// 阿里雲API的文件夾名稱(子文件夾)
String format = dateFormat.format(date) + "/";
// 文件名
String formats =String.valueOf(UUID.randomUUID());
// 創建一個可重用固定線程數的線程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
String[] resultArr = new String[2];
try {
// 分片上傳
folder =folder +"/"+ format;
// 文件名
String fileName = file.getName();
// 文件擴展名
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
// 最終文件名:UUID + 文件擴展名
fileName = formats + fileExtension;
// 上傳路徑 如:appversion/20200723/a3662009-897c-43ea-a6d8-466ab8310c6b.apk
// objectName表示上傳文件到OSS時需要指定包含文件後綴在內的完整路徑,例如abc/efg/123.jpg
String objectName = folder + fileName;
System.out.println("文件路徑--》》"+objectName);
// 文件大小
long fileSize = file.length();
// 創建上傳Object的Metadata
ObjectMetadata metadata = new ObjectMetadata();
// 指定該Object被下載時的網頁的緩存行為
metadata.setCacheControl("no-cache");
// 指定該Object下設置Header
metadata.setHeader("Pragma", "no-cache");
// 指定該Object被下載時的內容編碼格式
metadata.setContentEncoding("utf-8");
// 文件的MIME,定義文件的類型及網頁編碼,決定瀏覽器將以什麼形式、什麼編碼讀取文件。如果用戶沒有指定則根據Key或文件名的擴展名生成,
// 如果沒有擴展名則填默認值application/octet-stream
metadata.setContentType(getContentType(fileExtension));
// 指定該Object被下載時的名稱(指示MINME用戶代理如何顯示附加的文件,打開或下載,及文件名稱)
metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
// 創建對象
request = new (bucketName, objectName, metadata);
// 初始化分片
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 返回uploadId,它是分片上傳事件的唯一標識,您可以根據這個uploadId發起相關的操作,如取消分片上傳、查詢分片上傳等
String uploadId = upresult.getUploadId();
// partETags是PartETag的集合。PartETag由分片的ETag和分片號組成
List<PartETag> partETags = Collections.synchronizedList(new ArrayList<>());
// 計算文件有多少個分片
final long partSize = 1 * 1024 * 1024L; // 1MB
long fileLength = file.length();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
if (partCount > 10000) {
throw new RuntimeException("文件過大");
}
// 遍歷分片上傳
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
int partNumber = i + 1;
// 實現並啟動線程
executorService.execute(new Runnable() {
@Override
public void run() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
// 跳過已經上傳的分片
inputStream.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(objectName);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInputStream(inputStream);
// 設置分片大小。除了最後一個分片沒有大小限制,其他的分片最小為100 KB。
uploadPartRequest.setPartSize(curPartSize);
// 設置分片號。每一個上傳的分片都有一個分片號,取值范圍是1~10000,如果超出這個范圍,OSS將返回InvalidArgument的錯誤碼。
uploadPartRequest.setPartNumber(partNumber);
// 每個分片不需要按順序上傳,甚至可以在不同客戶端上傳,OSS會按照分片號排序組成完整的文件。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//每次上傳分片之後,OSS的返回結果會包含一個PartETag。PartETag將被保存到PartETags中。
synchronized (partETags) {
partETags.add(uploadPartResult.getPartETag());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
}
// 等待所有的分片完成
// shutdown方法:通知各個任務(Runnable)的運行結束
executorService.shutdown();
while (!executorService.isTerminated()) {
try {
// 指定的時間內所有的任務都結束的時候,返回true,反之返回false,返回false還有執行完的任務
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
// 立即關閉所有執行中的線程
// executorService.shutdownNow();
// 驗證是否所有的分片都完成
if (partETags.size() != partCount) {
throw new IllegalStateException("文件的某些部分上傳失敗!");
}
// 完成分片上傳 進行排序。partETags必須按分片號升序排列
Collections.sort(partETags, new Comparator<PartETag>() {
@Override
public int compare(PartETag o1, PartETag o2) {
return o1.getPartNumber() - o2.getPartNumber();
}
});
// 創建對象
// 在執行完成分片上傳操作時,需要提供所有有效的partETags。OSS收到提交的partETags後,會逐一驗證每個分片的有效性。當所有的數據分片驗證通過後,OSS將把這些分片組合成一個完整的文件
= new (bucketName, objectName, uploadId, partETags);
// 設置文件訪問許可權
// .setObjectACL(CannedAccessControlList.PublicRead);
// 完成上傳
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload();
if (completeMultipartUploadResult != null) {
// 解析結果
resultArr[0] = completeMultipartUploadResult.getETag();
resultArr[1] = objectName;
return resultArr;
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("上傳阿里雲OSS伺服器異常." + e.getMessage());
} finally {
// 關閉OSSClient
ossClient.shutdown();
}
return null;
}
/**
* MultipartFile 轉 File
*
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) {
try {
File toFile;
if (file != null && file.getSize() > 0) {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
return toFile;
}
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 獲取流文件
*
* @param ins
* @param file
*/
public static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲取阿里雲OSS客戶端對象
*
* @return ossClient
*/
public static OSS getOSSClient() {
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// 連接空閑超時時間,超時則關閉
conf.setIdleConnectionTime(1000);
return new OSSClientBuilder().build("自己阿里雲的endpoint", "自己阿里雲的access_key_id", "自己阿里雲的access_key_secret", conf);
}
/**
* 獲得url鏈接
*
* @param bucketName 桶名稱
* @param key Bucket下的文件的路徑名+文件名 如:"appversion/20200723/a3662009-897c-43ea-a6d8-466ab8310c6b.apk"
* @return 圖片鏈接:http://xxxxx.oss-cn-beijing.aliyuncs.com/test/headImage/1546404670068899.jpg?Expires=1861774699&OSSAccessKeyId=****=p%2BuzEEp%2F3JzcHzm%2FtAYA9U5JM4I%3D
* (Expires=1861774699&OSSAccessKeyId=LTAISWCu15mkrjRw&Signature=p%2BuzEEp%2F3JzcHzm%2FtAYA9U5JM4I%3D 分別為:有前期、keyID、簽名)
*/
public static String getUrl(String bucketName, String key) {
// 設置URL過期時間為10年 3600L*1000*24*365*10
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
OSS ossClient = getOSSClient();
// 生成URL
URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
return url.toString().substring(0, url.toString().lastIndexOf("?"));
}
/**
* 刪除本地臨時文件
*
* @param file
*/
public static void deleteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
/**
* 通過文件名判斷並獲取OSS服務文件上傳時文件的contentType
*
* @param fileExtension 文件名擴展名
* @return 文件的contentType
*/
public static String getContentType(String fileExtension) {
// 文件的後綴名
if (".bmp".equalsIgnoreCase(fileExtension)) {
return "image/bmp";
}
if (".gif".equalsIgnoreCase(fileExtension)) {
return "image/gif";
}
if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
|| ".png".equalsIgnoreCase(fileExtension)) {
return "image/jpeg";
}
if (".html".equalsIgnoreCase(fileExtension)) {
return "text/html";
}
if (".txt".equalsIgnoreCase(fileExtension)) {
return "text/plain";
}
if (".vsd".equalsIgnoreCase(fileExtension)) {
return "application/vnd.visio";
}
if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
return "application/vnd.ms-powerpoint";
}
if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
return "application/msword";
}
if (".xml".equalsIgnoreCase(fileExtension)) {
return "text/xml";
}
if (".mp4".equalsIgnoreCase(fileExtension)) {
return "video/mp4";
}
// android
if (".apk".equalsIgnoreCase(fileExtension)) {
return "application/vnd.android.package-archive";
}
// ios
if (".ipa".equals(fileExtension)) {
return "application/vnd.iphone";
}
// 默認返回類型
return "application/octet-stream";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
3.controller編寫
/**
* 上傳文件
*
* @param file 文件
* @return
* @throws IOException
*/
@ResponseBody
@RequestMapping(value = "/urevf", method = RequestMethod.POST, proces = "application/json;charset=UTF-8")
public JSONObject uploadRealEstateVideoFiles(@RequestParam(value = "file") MultipartFile file) throws IOException {
//此處的video_file為阿里雲OSS上最外層文件夾,自己新建即可
return FilesUploadUtil.obtainTheFileUploadResult(file, "video_file");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
④ oss自定義域名文件上傳
oss自定義域名文件上傳步驟如下:
1、登錄OSS管理控制台。
2、單擊Bucket列表,然後單擊目標Bucket名稱。
3、選擇文件管理>文件管理,單擊上傳文件。
4、在上傳文件頁面,完成基礎配置項。
5、單擊上傳文件,此時,可以在上傳列表頁簽查看各個文件的上傳進度。上傳完成後,可以在目標路徑下查看上傳文件的文件名、文件大小以及存儲類型等信息。
⑤ 小白使用阿里雲的oss實現文件雲存儲
項目需要上傳頭像,不想存在本地,之前用過阿里雲其他產品,這里就使用一下阿里雲的oss了,不得不說阿里雲的產品使用步驟真的很清晰.這里說一下我自己的使用步驟.
選擇對象存儲oss,進行開通
開通不要錢,有一定免費額度
許可權可以設置為公共讀
其實也就是兩步
1.引pom
2.復制黏貼大法
由於阿里雲一些密鑰配置和地域結點,bucket等是常量級的,所以我這里抽取出來放在了application.properties中, 方便管理 ,數據我手動加密了....大家換成自己的即可,
這些配置key=value key都是自己隨便寫的(也不是,起碼可以見名思意),只是為了我們配置的一個配置類可以利用spring的依賴注入填充value而已
說明:
說明:
我們阿里雲oss倉庫的url是一個咱們的倉庫+固定的地域結點值+咱們的文件名字,所以這里為了使上傳的文件名字不重復,使用了一個idworker,不知道的可以看一下 Twitter的 Snowflake(雪花演算法)
大家搭建完了可以用postman測試一下
ps:如果我們想方便管理或者後期擴展,我們這里也可以引入一個工具
我們可以用這個工具的一個方法String dirpath=new DateTime().tostring("yyyy/MM/dd");將當前的時間轉換為yyyy/MM/dd的格式,比如2020/02/03
這樣我們上傳的文件名字時候可以以這個dirpath作為我們的圖片所在的文件夾名稱,以分布式id生成器生成的id為名稱存儲.
下面看一下效果
⑥ 阿里雲oss 前端+後台方式-前端部分el-upload
axios封裝介面為非同步請求,使用el-upload默認上傳,在before-upload里請求需要使用同步,保證先獲取token再上傳。
1.過期時間設置久一點,默認 30s 。
2.本地連接測試去掉 callback ,不然就會報錯 private adress ... 。
3. key 格式為 dir 值加filename即 xxx/a.png ,格式不對會被處理成上傳內容為空,存不進去,返回碼正確。
4.設置 succes_action_status 為200,默認返回204。
5.保證 file 在提交內容中是最後一個。
⑦ vue 上傳文件到 阿里雲OSS,並獲取上傳進度
1.首先,安裝阿正絕尺里的包
初始化舉高一下配置,傳的參數data從後台獲取
2.使用element-ui的Upload作為上傳組件,http-request 來綁定自定義上傳的方宏備法Upload,action寫為空。 :before-upload="beforeUpload" 表示在上傳前做的事情,綁定了方法beforeUpload,我們可以在這個方法里獲取所需要的一些信息,比如簽名等等
data 例子如下
3.methods
從後台獲取第一步所需的數據
上傳方法
至此,上傳完成
⑧ 阿里雲OSS服務,怎麼做上傳進度包括大文件和小文件。
是使用PHP嗎?如果是的話你可以先獲取到要上傳的文件大小然後根據發送了多少得出百分比。具體OSS怎麼操作我不清楚,但是進度的話你可以這么做:
<?php
ob_start();
echo <<<EOT
<div style="width:80%;height:30px;margin:120px auto;border:solid 1px #CCC;">
<div id="load" style="width:0px;height:30px;background-color:#F00;"></div>
</div>
<script type="text/javascript">
function upload(load){
document.getElementById("load").style.width = load;
}
</script>
EOT;
ob_flush(); //這個必不可少
flush();
for($i=0;$i<=20;$i++){
//這個是計算出百分比的
$by = sprintf('%.0f%%',$i/20*100);
echo str_pad('<script>upload("'.$by.'");</script>', 4096);
ob_flush();
flush();
sleep(1); //暫停一秒
}
//運行之後就可以出現上傳的進度條了,OSS我不知道怎麼操作不過這段代碼或許對你有幫助!
?>