Stories

Detail Return Return

如何顯示防盜鏈的外站圖片 - Stories Detail

鄭重警告:本文止於技術研究,請勿在自己的生產環境使用他人圖片資源。

通常在開發測試環節,一些資源圖片會出現防盜鏈的錯誤提示,本文就通過前端基礎技術,實現基本的圖片跨站顯示效果。

防盜鏈的原理:

  1. 服務端通過請求頭的request.headers.referer來判斷是否是自己資源白名單的請求來源。
  2. 如果referer=null,則無法判斷來源,會正常顯示圖片。

所以基於以上理論,可以給圖片創造一個沒有referer的請求環境就可以實現了。

解決思路:

通過iframe來實現無referer的請求環境。

實現過程:

  1. 創建一個base64臨時資源,供iframe調用
  2. 在臨時資源中,請求圖片
  3. 圖片加載完成後,修改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>

此文為本人原創創新文章,轉發請註明來源。

user avatar chenwendeshuanggang Avatar mihuartuanr Avatar paidaxinghaimianbaobao Avatar
Favorites 3 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.