tencent cloud

Cloud Object Storage

uni-app 직접 전송 실습

PDF
포커스 모드
폰트 크기
마지막 업데이트 시간: 2026-02-09 15:11:14

소개

이 문서는 SDK에 의존하지 않고 간단한 코드를 사용하여 uni-app에서 직접 파일을 COS(Cloud Object Storage, COS)의 버킷에 전송하는 방법을 소개합니다.
설명:
이 문서 내용은 XML API의 PostObject 인터페이스PutObject 인터페이스를 기반으로 합니다.

솔루션 설명

실행 과정

1. 프론트엔드에서 파일을 선택하면, 프론트엔드가 확장자를 서버로 전송합니다.
2. 서버 측은 확장자에 따라 시간이 포함된 임의의 COS 파일 경로를 생성하고, 해당 PostObject policy 서명을 계산한 후 URL과 서명 정보를 프론트엔드에 반환합니다.
3. 프론트엔드에서 PostObject 인터페이스 또는 PutObject 인터페이스를 호출하여 파일을 COS에 직접 업로드합니다.

솔루션 장점

경로 보안: 서버 측에서 결정한 임의의 COS 파일 경로를 사용하면 기존 파일의 덮어쓰기 문제와 보안 위험을 효과적으로 방지할 수 있습니다.
다중 플랫폼 호환성: uni-app에서 제공하는 파일 선택 및 업로드 인터페이스를 사용하면 하나의 코드로 다중 플랫폼(Web/미니프로그램/App)에서 호환 가능합니다.

전제 조건

1. COS 콘솔에 로그인하여 버킷을 생성하고, Bucket(버킷 이름) 및 Region(리전 이름)을 획득하십시오. 자세한 내용은 버킷 생성 문서를 참고하십시오.
2. CAM 콘솔에 로그인하여 프로젝트의 SecretId 및 SecretKey를 획득하십시오.
3. 방금 생성한 버킷 상세 페이지로 이동하여, 보안 관리 > 크로스 도메인 액세스 CORS 설정 페이지에서 규칙 추가를 클릭하십시오. 구성 예시는 아래 그림과 같습니다. 자세한 내용은 크로스 도메인 액세스 설정 문서를 참고하십시오.


작업 절차

주의:
정식 배포 전에 서버 측에 웹사이트 자체에 대한 권한 검증 계층을 추가하는 것이 좋습니다.

프론트엔드 업로드

1. post-policy 예제(PostObject 서버 측 인터페이스) 또는 put-sign 예제(PutObject 서버 측 인터페이스)를 참고하여 임의 파일 경로 생성, 서명 계산 및 프론트엔드에 반환하는 데 사용합니다.
2. HBuilderX 기본 템플릿(자세한 내용은 HBuilderX 공식 웹사이트 참조)을 사용하여 uni-app 애플리케이션을 생성합니다.
3. 파일 > 새로 만들기 > 프로젝트를 선택합니다. 생성 완료 후, 해당 애플리케이션은 Vue 기반 프로젝트가 됩니다.
4. 다음 코드를 복사하여 pages/index/index.vue 파일 내용을 대체하고, 호출하는 post-policy 인터페이스 링크를 수정하여 자신의 서버 주소(즉, 1단계의 서버 인터페이스)로 지정합니다.
PostObject 업로드
PutObject 업로드
<template>
<view class="content">
<button type="default" @click="selectUpload">파일 선택하여 업로드</button>
<image v-if="fileUrl" class="image" :src="fileUrl"></image>
</view>
</template>

<script>
export default {
data() {
return {
title: 'Hello',
fileUrl: ''
};
},
onLoad() {

},
methods: {
selectUpload() {

var vm = this;

// 더 많은 문자 인코딩의 url encode 형식
var camSafeUrlEncode = function (str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\\(/g, '%28')
.replace(/\\)/g, '%29')
.replace(/\\*/g, '%2A');
};

// 업로드 경로 및 인증서 획득
var getUploadInfo = function (extName, callback) {
// 파일 확장자를 전달하여 백엔드에서 임의의 COS 객체 경로를 생성하고, 업로드 도메인 및 PostObject 인터페이스에 필요한 policy 서명을 반환합니다.
// 서버 측 예제 참조: https://github.com/tencentyun/cos-demo/tree/main/server/post-policy
uni.request({
url: 'http://127.0.0.1:3000/post-policy?ext=' + extName,
success: (res) => {
// 반환 형식이 올바른지 확인
console.log(res);
callback && callback(null, res.data);
},
error(err) {
callback && callback(err);
},
});
};

// 업로드 요청 시작, PostObject 인터페이스를 사용하여 업로드하며 policy 서명으로 보호합니다.
// 인터페이스 문서:https://www.tencentcloud.com/document/product/436/14690#.E7.AD.BE.E5.90.8D.E4.BF.9D.E6.8A.A4
var uploadFile = function (opt, callback) {
var formData = {
key: opt.cosKey,
policy: opt.policy, // 이 값은 policy의 base64 문자열을 전달합니다.
success_action_status: 200,
'q-sign-algorithm': opt.qSignAlgorithm,
'q-ak': opt.qAk,
'q-key-time': opt.qKeyTime,
'q-signature': opt.qSignature,
};
// 서버 측에서 임시 키를 생성한 경우 x-cos-security-token을 전달해야 합니다.
if (opt.securityToken) formData['x-cos-security-token'] = opt.securityToken;
uni.uploadFile({
url: 'https://' + opt.cosHost, //예시일 뿐, 실제 인터페이스 주소가 아닙니다.
filePath: opt.filePath,
name: 'file',
formData: formData,
success: (res) => {
if (![200, 204].includes(res.statusCode)) return callback && callback(res);
var fileUrl = 'https://' + opt.cosHost + '/' + camSafeUrlEncode(opt.cosKey).replace(/%2F/g, '/');
callback && callback(null, fileUrl);
},
error(err) {
callback && callback(err);
},
});
};

// 파일 선택
uni.chooseImage({
success: (chooseImageRes) => {
var file = chooseImageRes.tempFiles[0];
if (!file) return;
// 업로드할 로컬 파일 경로 가져오기
var filePath = chooseImageRes.tempFilePaths[0];
// 업로드한 파일의 확장자를 가져와 백엔드에서 임의의 COS 경로 주소를 생성합니다.
var fileName = file.name;
var lastIndex = fileName.lastIndexOf('.');
var extName = lastIndex > -1 ? fileName.slice(lastIndex + 1) : '';
// 사전 업로드용 도메인, 경로, 자격 증명 가져오기
getUploadInfo(extName, function (err, info) {
// 반환된 info 형식이 올바른지 확인
console.log(info);
// 파일 업로드
info.filePath = filePath;
uploadFile(info, function (err, fileUrl) {
vm.fileUrl = fileUrl;
});
});
}
});
},
}
}
</script>

<style>
.content {
padding: 20px 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.image {
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
</style>
<template>
<view class="content">
<button type="default" @click="selectUpload">파일 선택하여 업로드</button>
<image v-if="fileUrl" class="image" :src="fileUrl"></image>
</view>
</template>

<script>
export default {
data() {
return {
title: 'Hello',
fileUrl: ''
};
},
onLoad() {

},
methods: {
selectUpload() {
var vm = this;
// 더 많은 문자 인코딩의 url encode 형식
var camSafeUrlEncode = function (str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\\(/g, '%28')
.replace(/\\)/g, '%29')
.replace(/\\*/g, '%2A');
};
// 업로드 경로 및 인증서 획득
var getUploadInfo = function (extName, callback) {
// 파일 확장자를 전달하여 백엔드에서 임의의 COS 객체 경로를 생성하고, PUT Object 인터페이스에 사용할 서명을 반환합니다.
// 백엔드는 다음 항목을 반환해야 함: cosHost, cosKey, authorization, securityToken(선택 사항)
uni.request({
url: 'http://127.0.0.1:3000/put-signature?ext=' + extName,
success: (res) => {
// 반환 형식이 올바른지 확인
console.log(res);
callback && callback(null, res.data);
},
fail(err) {
callback && callback(err);
},
});
};
// 파일을 ArrayBuffer로 읽기
var readFileAsArrayBuffer = function (filePath, callback) {
uni.getFileSystemManager().readFile({
filePath: filePath,
success: (res) => {
callback && callback(null, res.data); // res.data는 ArrayBuffer입니다
},
fail(err) {
callback && callback(err);
}
});
};
// 업로드 요청 시작, PUT Object 인터페이스 사용
// 인터페이스 문서:https://www.tencentcloud.com/document/product/436/7749
var uploadFile = function (opt, fileData, callback) {
var headers = {
'Authorization': opt.authorization, // 서명 정보
'Content-Type': opt.contentType || 'application/octet-stream'
};
// 서버 측에서 임시 키를 생성한 경우 x-cos-security-token을 전달해야 합니다.
if (opt.securityToken) {
headers['x-cos-security-token'] = opt.securityToken;
}
console.log('업로드 요청 정보:', {
url: 'https://' + opt.cosHost + '/' + opt.cosKey,
headers: headers
});

uni.request({
url: 'https://' + opt.cosHost + '/' + opt.cosKey,
method: 'PUT',
header: headers,
data: fileData, // ArrayBuffer 형식
success: (res) => {
console.log('업로드 응답:', res);
if (![200, 204].includes(res.statusCode)) {
console.error('업로드 실패, 상태 코드:', res.statusCode);
return callback && callback(res);
}
var fileUrl = 'https://' + opt.cosHost + '/' + camSafeUrlEncode(opt.cosKey).replace(/%2F/g, '/');
callback && callback(null, fileUrl);
},
fail(err) {
console.error('업로드 요청 실패:', err);
callback && callback(err);
},
});
};

// 파일 선택
uni.chooseImage({
success: (chooseImageRes) => {
var file = chooseImageRes.tempFiles[0];
if (!file) return;
// 업로드할 로컬 파일 경로 가져오기
var filePath = chooseImageRes.tempFilePaths[0];
// 업로드한 파일의 확장자를 가져와 백엔드에서 임의의 COS 경로 주소를 생성합니다.
var fileName = file.name;
var lastIndex = fileName.lastIndexOf('.');
var extName = lastIndex > -1 ? fileName.slice(lastIndex + 1) : '';
// 사전 업로드용 도메인, 경로, 서명 가져오기
getUploadInfo(extName, function (err, info) {
if (err) {
console.error('업로드 정보 가져오기 실패:', err);
return;
}
// 반환된 info 형식이 올바른지 확인
console.log(info);
// 파일을 ArrayBuffer로 읽기
readFileAsArrayBuffer(filePath, function (err, fileData) {
if (err) {
console.error('파일 읽기 실패:', err);
return;
}
// 파일 업로드
uploadFile(info, fileData, function (err, fileUrl) {
if (err) {
console.error('업로드 실패:', err);
return;
}
vm.fileUrl = fileUrl;
console.log('업로드 성공:', fileUrl);
});
});
});
}
});
},
}
}
</script>

<style>
.content {
padding: 20px 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

.image {
margin-top: 20px;
margin-left: auto;
margin-right: auto;
}
</style>
5. HBuilderX에서 실행 > 브라우저에서 실행 > Chrome을 선택하면 브라우저에서 파일을 선택하여 업로드할 수 있습니다.
6. 실행 효과는 다음 그림과 같습니다.
프로젝트 생성:
uni-app 프로젝트 생성


직접 전송 효과:
uni-app 직접 전송 효과



관련 문서

도움말 및 지원

문제 해결에 도움이 되었나요?

피드백