一、為什么使用 AVIF 圖片格式?
優勢點 | 說明 |
高壓縮率 | 在相似質量下,AVIF 文件比 JPEG/PNG/WebP 更小,能有效節省帶寬和存儲空間。 |
更高畫質 | 即使在低碼率下也能保持清晰細節,減少壓縮帶來的馬賽克或模糊問題。 |
支持透明度 | 像 PNG 一樣支持 Alpha 通道透明效果,且文件更小。 |
支持 HDR | 支持高動態范圍(HDR)色彩,亮部與暗部細節表現更出色。 |
支持動畫 | 支持多幀動畫,體積遠小于 GIF,可實現流暢動畫效果。 |
開源免費 | 基于開放標準,無需支付版權費用,適合廣泛應用。 |
更好的色彩表現 | 支持更高位深(如 10 位、12 位色深),色彩過渡更加自然。 |
瀏覽器支持不斷提升 | 已被 Chrome、Firefox、Safari、Edge 等主流瀏覽器廣泛支持,兼容性持續提升。 |
采用 AVIF 圖片格式,可以大幅提升網頁加載性能、優化視覺體驗,并有效降低服務器及流量成本。
二、圖片上傳為 PNG/JPG,為什么最終返回的是 AVIF?
我們上傳至 AWS S3 桶中的圖片文件,最初是以傳統格式(如 PNG、JPG)存在的。但用戶最終訪問時,返回的是 AVIF 格式,主要是因為配置了以下動態處理流程:
-
攔截請求與格式判斷
-
當瀏覽器請求圖片資源時,AWS 會攔截請求,檢測瀏覽器是否支持 AVIF 格式。
-
如果支持,將在 S3 中查找對應的 AVIF 文件。
2. 動態生成 AVIF 圖片
- 如果 S3 桶中已有對應的 AVIF 圖片,直接返回。
- 如果沒有現成的 AVIF 圖片,則根據用戶請求的源圖片(PNG/JPG),實時生成一張新的 AVIF 圖片,并保存到 S3 桶中,隨后返回給用戶。
3. 兼容老瀏覽器
-
如果瀏覽器不支持 AVIF,則直接返回原始格式的圖片(如 PNG、JPG),確保訪問兼容性。
三、替換同名圖片后,是否還會訪問到舊的 AVIF 圖片?
不會。
為了避免用戶訪問到緩存中的老圖片,系統在圖片上傳階段進行了以下處理:
-
當上傳新的同名圖片時,AWS 會自動檢測并刪除已有的同名 AVIF 圖片資源。
-
這樣一來,舊版 AVIF 圖片被清除。
-
當用戶下次訪問時,因找不到舊的 AVIF 圖片,系統會根據新的源圖重新生成新的 AVIF 文件并返回。
-
從而確保用戶訪問到的永遠是最新版本的圖片內容。
? 此機制有效避免了 CDN 緩存失效等待問題,大大簡化了圖片更新和運維管理流程。
四、我們訪問的圖片后綴明明是jpg 或者png 為什么我們下載下來是avif
-
瀏覽器發起請求,比如?
GET https://yourdomain.com/path/image.jpg
-
**請求頭(Accept)**中會帶上瀏覽器支持的圖片格式,比如:
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
瀏覽器告訴服務器:"我可以接受 avif 格式哦!"
-
Lambda@Edge 或 CDN(如 CloudFront)攔截了請求,根據請求頭里的?
Accept
?判斷,發現瀏覽器支持?avif
,于是就做了智能格式替換:
-
雖然你請求的是?
image.jpg
-
但是它在 S3 或緩存中找到了對應的?
image.avif
-
返回的時候,偷偷換了資源文件,返回的是?
AVIF
?內容
-
當用戶下次訪問時,因找不到舊的 AVIF 圖片,系統會根據新的源圖重新生成新的 AVIF 文件并返回。
-
從而確保用戶訪問到的永遠是最新版本的圖片內容。
-
?返回的 HTTP 響應里,重要的是Content-Type?頭:
Content-Type: image/avif
瀏覽器收到的是一個 AVIF 格式的數據,雖然 URL 還是?.jpg
,但實際上它知道應該用 AVIF 解碼來展示。
為什么下載下來是 AVIF?
-
你點右鍵下載時,瀏覽器是根據返回的?
Content-Type
?類型來確定文件格式的,不是根據 URL 后綴。 -
Content-Type: image/avif
,所以瀏覽器保存成了?.avif
?文件,即使鏈接上還是?.jpg
。 -
瀏覽器內部已經知道這張圖實際上是 AVIF 格式了。
總結一句話:
請求是 JPG,返回是 AVIF,靠的是 HTTP Content-Type,瀏覽器根據返回類型進行識別和保存。
五、補充說明
-
動態生成 AVIF 圖片一般通過?AWS Lambda@Edge?來實現,支持實時生成并自動回寫存儲。
-
項目如果對首屏加載性能要求極高,可以結合 CDN 對 AVIF 圖片進行緩存加速。
-
建議統一規范圖片命名,避免因頻繁重名導致過多歷史資源堆積,影響桶管理效率。
要通過?AWS Lambda@Edge?動態把 S3 上的 PNG、JPG 轉成 AVIF 圖片,基本思路是:
-
攔截圖片請求(比如?.jpg、.png)
-
判斷瀏覽器?
Accept
?請求頭是否支持?image/avif
-
如果支持:
-
查詢 S3 中是否已有對應?
.avif
?文件 -
如果沒有,就實時讀取源圖,轉碼成?
.avif
,存回 S3,再返回 -
如果不支持:
-
直接返回原圖
下面是一個簡單版的 Node.js(AWS Lambda@Edge)腳本示例:
const AWS = require('aws-sdk');
const sharp = require('sharp'); // sharp 用于圖片處理// S3 客戶端
const s3 = new AWS.S3({ region: 'your-bucket-region' });const BUCKET = 'your-bucket-name';exports.handler = async (event, context, callback) => {const request = event.Records[0].cf.request;const headers = request.headers;const uri = request.uri;console.log('Request URI:', uri);// 只處理 jpg/png 請求if (!uri.match(/\.(jpg|jpeg|png)$/i)) {return callback(null, request);}// 檢查瀏覽器是否支持 AVIFconst acceptHeader = headers['accept'] ? headers['accept'][0].value : '';const supportsAvif = acceptHeader.includes('image/avif');if (!supportsAvif) {// 不支持 AVIF,直接返回原圖console.log('Browser does not support AVIF');return callback(null, request);}// 構造 avif 文件的路徑const avifUri = uri.replace(/\.(jpg|jpeg|png)$/i, '.avif');try {// 先檢查 AVIF 是否已經存在await s3.headObject({Bucket: BUCKET,Key: decodeURIComponent(avifUri).substring(1), // 去掉開頭的 /}).promise();// 已存在,修改請求路徑,返回 avifconsole.log('AVIF exists, serving AVIF');request.uri = avifUri;return callback(null, request);} catch (error) {if (error.code !== 'NotFound') {// 其他異常console.error('Error checking AVIF file:', error);return callback(error);}console.log('AVIF not found, generating dynamically');// AVIF 不存在,讀取源圖const originImage = await s3.getObject({Bucket: BUCKET,Key: decodeURIComponent(uri).substring(1),}).promise();// 用 sharp 轉 AVIFconst avifBuffer = await sharp(originImage.Body).avif({ quality: 50 }).toBuffer();// 寫回 S3,生成新的 AVIF 文件await s3.putObject({Bucket: BUCKET,Key: decodeURIComponent(avifUri).substring(1),Body: avifBuffer,ContentType: 'image/avif',CacheControl: 'public, max-age=31536000', // 設置長緩存}).promise();// 修改請求路徑,返回新的 AVIFrequest.uri = avifUri;return callback(null, request);}
};