Skip to main content

OSS Pre-sign Upload API

Overview

The pre-sign upload mechanism allows clients (Web, Mobile, Desktop) to upload files directly to Alibaba Cloud OSS using a signed URL. This eliminates the need for clients to hold AccessKeys or manually set signature headers, ensuring a secure and streamlined upload process.

Workflow:

  1. Step 1: The client requests a pre-signed PUT URL from the server.
  2. The server responds with an upload_url (signed PUT address) and an access_url (the public or CDN address to access the file after upload).
  3. Step 2: The client directly uploads the file body to the upload_url using an HTTP PUT request.
  4. Once the upload is complete, the file becomes available via the access_url.

Step 1: Get Pre-Signed Upload URL

Request

POST /api/oss/presign-put
Content-Type: application/json
Apikey: YOUR_API_KEY

Request Body

FieldTypeRequiredDescription
filenamestringYesThe filename (including extension), used to infer Content-Type and generate the storage path. Examples:"photo.jpg", "video.mp4"
content_typestringYesThe Content-Type of the file. Supported values are listed in the Supported File Types section.
expire_secondsintNoThe validity period of the pre-signed URL in seconds. Range: 60-7200. Default: 3600.

Example Request

{
"filename": "my-photo.jpg",
"content_type": "image/jpeg",
"expire_seconds": 3600
}

Response

Response Body

FieldTypeDescription
upload_urlstringThe pre-signed PUT URL. The client must PUT the file content directly to this address.
access_urlstringThe URL through which the file can be accessed after upload (via CDN or custom domain).
object_keystringThe OSS object path.
content_typestringThe Content-Type the clientmust set during the PUT request. This must match the actual request header exactly.
expire_atintThe expiration timestamp of the pre-signed URL (Unix timestamp, in seconds).

Example Response

{
"code": 0,
"data": {
"upload_url": "https://bucket.oss-us-west-1.aliyuncs.com/uploads/2026/03/25/a1b2c3d4.jpg?OSSAccessKeyId=xxx&Expires=1742954400&Signature=yyy",
"access_url": "https://cdn.example.com/uploads/2026/03/25/a1b2c3d4.jpg",
"object_key": "uploads/2026/03/25/a1b2c3d4.jpg",
"content_type": "image/jpeg",
"expire_at": 1742954400
}
}

Step 1 (Batch): Batch Get Pre-Signed Upload URLs

Request

POST /api/oss/presign-put/batch
Content-Type: application/json
Apikey: YOUR_API_KEY

Request Body

FieldTypeRequiredDescription
filesarrayYesA list of files to upload (1-20 items).
files[].filenamestringYesThe filename (including extension).
files[].content_typestringYesThe Content-Type of the file. Supported values are listed in the Supported File Types section.
expire_secondsintNoA unified validity period for all URLs in seconds. Range: 60-7200. Default: 3600.

Example Request

{
"files": [
{ "filename": "cover.png", "content_type": "image/png" },
{ "filename": "trailer.mp4", "content_type": "video/mp4" },
{ "filename": "song.mp3", "content_type": "audio/mpeg" }
],
"expire_seconds": 1800
}

Response

Response Body

FieldTypeDescription
totalintTotal number of files requested.
successintNumber of successfully generated pre-signed URLs.
failedintNumber of failed generations.
itemsarrayA list of pre-signed results, corresponding 1:1 with the requested files array.
items[].upload_urlstringThe pre-signed PUT URL.
items[].access_urlstringThe URL through which the file can be accessed after upload.
items[].object_keystringThe OSS object path.
items[].content_typestringThe Content-Type the client must use during the PUT request.
items[].expire_atintExpire time (Unix timestamp, in seconds).

Example Response

{
"code": 0,
"data": {
"total": 3,
"success": 3,
"failed": 0,
"items": [
{
"upload_url": "https://bucket.oss-us-west-1.aliyuncs.com/uploads/2026/03/25/e5f6a7b8.png?...",
"access_url": "https://cdn.example.com/uploads/2026/03/25/e5f6a7b8.png",
"object_key": "uploads/2026/03/25/e5f6a7b8.png",
"content_type": "image/png",
"expire_at": 1742952600
},
{
"upload_url": "https://bucket.oss-us-west-1.aliyuncs.com/uploads/2026/03/25/c9d0e1f2.mp4?...",
"access_url": "https://cdn.example.com/uploads/2026/03/25/c9d0e1f2.mp4",
"object_key": "uploads/2026/03/25/c9d0e1f2.mp4",
"content_type": "video/mp4",
"expire_at": 1742952600
},
{
"upload_url": "https://bucket.oss-us-west-1.aliyuncs.com/uploads/2026/03/25/a3b4c5d6.mp3?...",
"access_url": "https://cdn.example.com/uploads/2026/03/25/a3b4c5d6.mp3",
"object_key": "uploads/2026/03/25/a3b4c5d6.mp3",
"content_type": "audio/mpeg",
"expire_at": 1742952600
}
]
}
}

Step 2: Upload File to OSS

After obtaining the pre-signed URL (Step 1), the client must perform a direct upload to OSS.

Request

PUT {upload_url}
Content-Type: {content_type}

Request Headers

HeaderTypeRequiredDescription
Content-TypestringYesMust strictly match the content_type returned in the response from Step 1.

Request Body

  • Binary Data: The actual file content to be uploaded (the raw byte stream).

Example Request

# Replace {upload_url} and {content_type} with the values returned in Step 1
curl -X PUT \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg \
"https://bucket.oss-us-west-1.aliyuncs.com/uploads/..."

Response

Response Status

  • 200 OK: Upload successful.
  • 403 Forbidden: Signature mismatch or expired URL. Usually caused by an incorrect Content-Type header or the URL exceeding its expire_seconds.

Example Response

HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
x-oss-request-id: 56345880014522
Date: Wed, 25 Mar 2026 12:00:00 GMT

(Note: A successful OSS PUT response usually contains an empty body.)


Supported File Types

TypeExtensionContent-Type
Image.jpg / .jpegimage/jpeg
Image.pngimage/png
Image.gifimage/gif
Image.webpimage/webp
Image.bmpimage/bmp
Video.mp4video/mp4
Video.movvideo/quicktime
Video.avivideo/x-msvideo
Video.mkvvideo/x-matroska
Video.webmvideo/webm
Audio.mp3audio/mpeg
Audio.wavaudio/wav
Audio.aacaudio/aac
Audio.m4aaudio/mp4
Document.pdfapplication/pdf

File extensions that are not in the whitelist will return a 400 error.


Client Upload Examples

cURL

# 1. Get the pre-signed URL
curl -X POST https://api.example.com/api/oss/presign-put \
-H "Content-Type: application/json" \
-H "Apikey: YOUR_API_KEY" \
-d '{"filename": "photo.jpg", "content_type": "image/jpeg"}'

# 2. Upload the file directly using the returned upload_url (ensure Content-Type strictly matches)
curl -X PUT \
-H "Content-Type: image/jpeg" \
-T ./photo.jpg \
"<upload_url>"

JavaScript (Web Frontend)

// 1. Get the pre-signed URL
const presignResp = await fetch('/api/oss/presign-put', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Apikey': 'YOUR_API_KEY',
},
body: JSON.stringify({
filename: file.name,
content_type: file.type,
expire_seconds: 3600,
}),
});
const { data } = await presignResp.json();

// 2. Direct PUT upload
const uploadResp = await fetch(data.upload_url, {
method: 'PUT',
headers: {
'Content-Type': data.content_type,
},
body: file, // File Object
});

if (uploadResp.ok) {
console.log('Upload successful. Access URL:', data.access_url);
}

JavaScript (XMLHttpRequest with Progress)

async function uploadWithProgress(file, onProgress) {
// 1. Get the pre-signed URL
const presignResp = await fetch('/api/oss/presign-put', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Apikey': 'YOUR_API_KEY',
},
body: JSON.stringify({ filename: file.name, content_type: file.type }),
});
const { data } = await presignResp.json();

// 2. Upload via XMLHttpRequest (supports progress callback)
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('PUT', data.upload_url);
xhr.setRequestHeader('Content-Type', data.content_type);

xhr.upload.onprogress = (e) => {
if (e.lengthComputable && onProgress) {
onProgress(Math.round((e.loaded / e.total) * 100));
}
};

xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve({ accessUrl: data.access_url, objectKey: data.object_key });
} else {
reject(new Error(`Upload failed: ${xhr.status}`));
}
};

xhr.onerror = () => reject(new Error('Network error'));
xhr.send(file);
});
}

// Usage
uploadWithProgress(fileInput.files[0], (pct) => {
console.log(`Upload progress: ${pct}%`);
}).then((result) => {
console.log('Access URL:', result.accessUrl);
});

Swift (iOS)

func presignUpload(file: Data, filename: String) async throws -> String {
// 1. Get the pre-signed URL
var presignReq = URLRequest(url: URL(string: "\(baseURL)/api/oss/presign-put")!)
presignReq.httpMethod = "POST"
presignReq.setValue("application/json", forHTTPHeaderField: "Content-Type")
presignReq.setValue("YOUR_API_KEY", forHTTPHeaderField: "Apikey")
presignReq.httpBody = try JSONEncoder().encode([
"filename": filename,
"content_type": "image/jpeg"
])

let (data, _) = try await URLSession.shared.data(for: presignReq)
let resp = try JSONDecoder().decode(PresignResponse.self, from: data)

// 2. Direct PUT upload
var uploadReq = URLRequest(url: URL(string: resp.data.uploadURL)!)
uploadReq.httpMethod = "PUT"
uploadReq.setValue(resp.data.contentType, forHTTPHeaderField: "Content-Type")
uploadReq.httpBody = file

let (_, uploadResp) = try await URLSession.shared.data(for: uploadReq)
guard let httpResp = uploadResp as? HTTPURLResponse,
(200..<300).contains(httpResp.statusCode) else {
throw URLError(.badServerResponse)
}

return resp.data.accessURL
}

Kotlin (Android)

suspend fun presignUpload(file: File): String {
val client = OkHttpClient()

// 1. Get the pre-signed URL
val presignBody = """{"filename": "${file.name}", "content_type": "image/jpeg"}"""
.toRequestBody("application/json".toMediaType())

val presignReq = Request.Builder()
.url("$baseUrl/api/oss/presign-put")
.header("Apikey", "YOUR_API_KEY")
.post(presignBody)
.build()

val presignResp = client.newCall(presignReq).await()
val data = JSONObject(presignResp.body!!.string())
.getJSONObject("data")

val uploadUrl = data.getString("upload_url")
val contentType = data.getString("content_type")
val accessUrl = data.getString("access_url")

// 2. Direct PUT upload
val fileBody = file.asRequestBody(contentType.toMediaType())
val uploadReq = Request.Builder()
.url(uploadUrl)
.put(fileBody)
.build()

val uploadResp = client.newCall(uploadReq).await()
if (!uploadResp.isSuccessful) {
throw IOException("Upload failed: ${uploadResp.code}")
}

return accessUrl
}

Error Codes

HTTP Status CodeDescription
400Parameter error: missing filename, extension not in whitelist, etc.
401Authentication failed
500Server error: OSS client not initialized, signature generation failed, etc.
Ready to Start?

Get started by Purchasing an API Key Now to unlock full access to the HitPaw Enhancement API.