郑重警告:本文止于技术研究,请勿在自己的生产环境使用他人图片资源。
通常在开发测试环节,一些资源图片会出现防盗链的错误提示,本文就通过前端基础技术,实现基本的图片跨站显示效果。
防盗链的原理:
- 服务端通过请求头的
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>
此文为本人原创创新文章,转发请注明来源。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。