101 lines
2.6 KiB
Markdown
101 lines
2.6 KiB
Markdown
---
|
||
title: 使用签名URL上传文件的一个注意事项
|
||
description: 使用签名URL上传文件时,需要特别小心处理请求的Content-Type头
|
||
date: 2025-02-21T21:59:00+08:00
|
||
slug: signurl
|
||
categories:
|
||
- 奇技淫巧
|
||
tags: [
|
||
"前端",
|
||
"后端",
|
||
"JavaScript",
|
||
"Node.js",
|
||
"OSS",
|
||
"建站",
|
||
"签名URL"
|
||
]
|
||
lastmod: 2025-02-21T22:13:00+08:00
|
||
---
|
||
如果后端用阿里云OSS SDK生成了签名URL,前端直接使用签名URL上传文件时,为了避免把文件传给后端服务器占据内存,常见的实践是,前端把文件类型传给后端,后端根据文件类型生成带Content-Type头的签名URL,前端直接使用签名URL上传文件。
|
||
|
||
这里有一个问题,如果我们不手动指定后端签名使用的Content-Type头,那么后端签名时会认为请求不具有Content-Type头。但是前端在使用签名URL进行上传时,浏览器会自动设置Content-Type头为指定的文件类型,就会导致OSS服务器校验签名URL失败,返回403错误。
|
||
|
||
所以,<strong>后端在生成签名URL时,必须手动指定Content-Type头。</strong>最佳的实践是,前端把文件的MIME类型传给后端,后端根据MIME类型生成带Content-Type头的签名URL。
|
||
|
||
后端:
|
||
```js
|
||
const oss = require('ali-oss')
|
||
const express = require('express')
|
||
const app = express()
|
||
const client = new oss({
|
||
accessKeyId: 'yourAccessKeyId',
|
||
// ...
|
||
authorizationV4: true // 使用V4签名
|
||
})
|
||
|
||
app.use(express.json())
|
||
|
||
app.post('/get-signed-url', (req, res) => {
|
||
const { type } = req.body
|
||
const url = client.signatureUrlV4(
|
||
'PUT',
|
||
20, // 有效期20秒
|
||
{
|
||
headers: {
|
||
'Content-Type': type // 签名中指定Content-Type头
|
||
}
|
||
}
|
||
)
|
||
res.json({ url })
|
||
})
|
||
```
|
||
前端:
|
||
```js
|
||
const file = document.querySelector('input[type="file"]').files[0]
|
||
const type = file.type || 'application/octet-stream' // 获取文件的MIME类型
|
||
const url = await fetch('/get-signed-url', {
|
||
method: 'POST',
|
||
body: JSON.stringify({ type })
|
||
}).then(res => res.json())
|
||
|
||
const upload = await fetch(url, {
|
||
method: 'PUT',
|
||
body: file,
|
||
headers: {
|
||
'Content-Type': type // 必须保证跟签名的Content-Type头一致
|
||
}
|
||
})
|
||
```
|
||
这样就能保证上传的文件类型与签名URL的Content-Type头一致,不会出现403错误。
|
||
|
||
另外,我发现在签名URL中附带Authorization头,是无效操作,猜测Authorization头会被OSS服务器忽略。后端即使在签名时指定了Authorization头,前端不携带Authorization头也能上传成功。
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|