鄭重警告:本文止於技術研究,請勿在自己的生產環境使用他人圖片資源。
通常在開發測試環節,一些資源圖片會出現防盜鏈的錯誤提示,本文就通過前端基礎技術,實現基本的圖片跨站顯示效果。
防盜鏈的原理:
- 服務端通過請求頭的
request.headers.referer來判斷是否是自己資源白名單的請求來源。 - 如果referer=null,則無法判斷來源,會正常顯示圖片。
所以基於以上理論,可以給圖片創造一個沒有referer的請求環境就可以實現了。
解決思路:
通過iframe來實現無referer的請求環境。
實現過程:
- 創建一個base64臨時資源,供iframe調用
- 在臨時資源中,請求圖片
- 圖片加載完成後,修改iframe.height=img.height
源碼
base64臨時資源:
const src = 'http://test.com/test.png';
const html = `data:text/html;base64,${btoa(`<img src="${src}"/>`)}`
<iframe src="html"></iframe>
使用ResizeObserver監聽圖片高度
由於當前iframe裏只有一個圖片,所以監聽body高度即可(body有默認margin,後面需要清除樣式)。(ResizeObserver API)
var ro = new ResizeObserver(entries => {
for (let entry of entries) {
const data = {height: entry.contentRect.height};
window.parent?.postMessage({...data, window: 'parent'}, '*')
window.top?.postMessage({...data, window: 'top'}, '*')
}
})
ro.observe(document.body)
window.addEventListener("message", e => {
if (e.data.window === 'parent') {
iframe.style.height = e.data.height + 'px'
}
}, false)
完整代碼 (vue3 setup ts)
<script setup lang="ts">
import { onMounted, ref, withDefaults } from 'vue'
interface IProps {
src: string;
id?: string
}
const props = withDefaults(defineProps<IProps>(), {});
const iframe = ref(null)
onMounted(() => {
if (iframe.value) {
const html = `<style>body{margin:0;}</style>
<img src="${props.src}" style="display:block"/>
<script>
var ro = new ResizeObserver(entries => {
for (let entry of entries) {
const data = {height: entry.contentRect.height, id: "${props.id || props.src}"};
window.parent?.postMessage({...data, window: 'parent'}, '*')
window.top?.postMessage({...data, window: 'top'}, '*')
}
})
ro.observe(document.body)
<\/script>`
iframe.value.src = `data:text/html;base64,${btoa(html)}`
}
window.addEventListener("message", e => {
if (e.data.window === 'parent' && e.data.id === props.src && iframe.value) {
iframe.value.style.height = e.data.height + 'px'
}
}, false)
})
</script>
<template>
<iframe ref="iframe" style="display: block; border: 0;"></iframe>
</template>
此文為本人原創創新文章,轉發請註明來源。