開發者文件

整合動詞圖雲

本文說明如何在網頁、iOS 及 Android 應用程式中正確存取動詞圖雲的圖片網域, 包含必要的請求設定與使用注意事項。

使用規範

僅限 HTTP GET

圖片網域只開放 GET 請求,請勿使用 HEAD 或其他方法。

帶上 Referer(網頁)

在網頁中嵌入圖片時,確保瀏覽器帶上 Referer 標頭。

請勿頻繁重複請求

短時間大量請求相同圖片可能觸發 Cloudflare 防護機制。

App 環境(iOS / Android)發出的請求通常不含 Sec-Fetch-DestReferer,動詞圖雲會將其識別為合法的應用程式請求,無須額外設定即可正常存取。

網頁(HTML / JavaScript)

使用 <img> 標籤嵌入圖片

在 HTML 中嵌入圖片時,請加上 referrerpolicy 屬性,確保瀏覽器正確傳送 Referer 標頭,圖片才能順利顯示。

<img
  src="https://i.verb.tw/aBcD1234.jpg"
  referrerpolicy="no-referrer-when-downgrade"
  alt="圖片描述"
/>

使用 fetch() 下載圖片

const response = await fetch('https://i.verb.tw/aBcD1234.jpg');
const blob = await response.blob();
const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = 'aBcD1234.jpg';
a.click();
URL.revokeObjectURL(url);

在 Next.js / React 中使用

// 一般 <img> 標籤
<img
  src="https://i.verb.tw/aBcD1234.jpg"
  referrerPolicy="no-referrer-when-downgrade"
  alt="圖片描述"
/>

// Next.js <Image> 元件(需設定 remotePatterns)
// next.config.js
images: {
  remotePatterns: [
    { protocol: 'https', hostname: 'i.verb.tw' },
  ],
}

iOS(Swift)

iOS 的 URLSession 預設不帶 Sec-Fetch-Dest,動詞圖雲會視為合法的 App 請求,可直接存取,無需額外設定。

URLSession 原生下載

let url = URL(string: "https://i.verb.tw/aBcD1234.jpg")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
// 請使用 GET,勿使用 HEAD

let (data, _) = try await URLSession.shared.data(for: request)
let image = UIImage(data: data)

使用 Kingfisher

import Kingfisher

let url = URL(string: "https://i.verb.tw/aBcD1234.jpg")
imageView.kf.setImage(with: url)

使用 SDWebImage

import SDWebImage

let url = URL(string: "https://i.verb.tw/aBcD1234.jpg")
imageView.sd_setImage(with: url)

使用 Nuke

import Nuke
import NukeUI

// SwiftUI(推薦)
LazyImage(url: URL(string: "https://i.verb.tw/aBcD1234.jpg"))

// UIKit
let url = URL(string: "https://i.verb.tw/aBcD1234.jpg")!
Nuke.loadImage(with: url, into: imageView)

Kingfisher、SDWebImage 與 Nuke 皆內建磁碟與記憶體快取,能有效避免重複請求,強烈建議搭配使用。

Android(Kotlin)

Android 主流圖片載入函式庫預設使用 GET 請求,且不帶 Sec-Fetch-Dest,與動詞圖雲完全相容,可直接使用。

使用 Coil(推薦)

// build.gradle.kts
implementation("io.coil-kt:coil-compose:2.6.0")

// Jetpack Compose
AsyncImage(
    model = "https://i.verb.tw/aBcD1234.jpg",
    contentDescription = "圖片描述",
)

使用 Glide

Glide.with(context)
    .load("https://i.verb.tw/aBcD1234.jpg")
    .into(imageView)

使用 OkHttp 直接下載

val client = OkHttpClient()

val request = Request.Builder()
    .url("https://i.verb.tw/aBcD1234.jpg")
    .get() // 明確使用 GET,避免函式庫預設 HEAD
    .build()

client.newCall(request).enqueue(object : Callback {
    override fun onResponse(call: Call, response: Response) {
        val bytes = response.body?.bytes()
        val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes!!.size)
    }
    override fun onFailure(call: Call, e: IOException) {
        // 處理錯誤
    }
})

請確認你的 HTTP 客戶端不會自動發送 HEAD 預檢請求。部分舊版函式庫在下載前會先送 HEAD 確認檔案大小,這在動詞圖雲會受到限制。

常見問題

圖片回傳 403 或被重導向,該怎麼辦?

使用網頁 <img> 嵌入時,若缺少合法的 Referer 標頭,會被 Hotlink 保護攔截。 請在標籤加上 referrerpolicy="no-referrer-when-downgrade"

HEAD 請求回傳錯誤?

圖片網域僅開放 GET 請求,HEAD 方法受到限制。若你的函式庫預設使用 HEAD 確認資源,請將請求方法改為 GET。

存取突然被封鎖?

短時間內對相同圖片發送大量請求可能觸發 Cloudflare 自動防護,導致 IP 暫時受阻。 建議在應用程式端實作本地快取(Kingfisher、Glide、Coil 皆有內建),避免重複請求同一資源。

還有其他問題?

如遇整合問題或有特殊使用需求,歡迎與我們聯絡。

聯絡我們