Node.js 服务端如何实现图片防盗链 All In One
Node.js 服务端如何实现图片防盗链 All In One
How the Node.js server implements image anti-leeching
- 无扩图片展名 URL
- blob URL 一次性链接
- 设置有效期 链接
- 禁用缓存
- Referrer Policy,
referer
禁用 Iframe - CORS 白名单
动态生成的
blob
链接,过一段时间后,刷新页面回自动失效 🚀
fetch client
// <img id="img" data-src="http://localhost:3000/image" data-type="image/png" src="" alt="" />
function generatorBlobURL(url, type, img) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function(res) {
let blob = new Blob(
[xhr.response],
{'type' : type},
);
let urlBlob = URL.createObjectURL(blob);
img.src = urlBlob;
};
xhr.send();
}
window.onload = () => {
async function test() {
const img = document.querySelector('#img');
const url = `${img.dataset.src}`;
const url = `${img.dataset.type}`;
const res = await fetch(url).then(res => res.json())
// console.log(`res`, res, typeof res)
generatorBlobURL(res.url, type, img);
};
test()
}
express.js server
const express = require('express');
const app = express();
// middleware
app.use(function (req, res, next) {
// allow CORS request ✅
res.header("Access-Control-Allow-Origin", "*");
next();
});
app.get('/image', async (req, res) => {
// random cdn image link
const url = `https://cdn.xgqfrms.xyz/logo/icon.png`;
const json = {
url,
}
// 🚀 返回 JSON object
res.json(json)
});
const defaultPort = 3000;
const port = process.env.PORT || defaultPort
app.listen(port, () => {
console.log(`app is running on http://localhost:${port}`)
});
// https://cdn.xgqfrms.xyz/logo/icon.png
// http://localhost:3000/image
https://github.com/xgqfrms/learning/issues/24
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
// express.js set Access-Control-Allow-Origin
blob
url (blocked:other)
http://127.0.0.1:5501/iframe.html
http://127.0.0.1:5500/image.html
-
The blob link is a
temporary
link, if yourefresh
the page it will lost. Although you can open it in anew tab
of the same browser, but not support opening it in incognito mode. -
The reason is in
incognito mode
or a different browser, the blob link will lose itsreferer
or somecookie
message. -
blob链接是
临时链接
,刷新
页面就会丢失; 虽然您可以在同一浏览器
的新选项卡
中打开它,但不支持
以隐身模式
打开它。 -
原因是在
隐身模
式或不同的浏览器
中,blob 链接将丢失
其引用者
或某些 cookie
消息。
https://stackoverflow.com/questions/72549170/blob-links-are-blocked
demos
http://127.0.0.1:5500/image.html
blob:http://127.0.0.1:5500/a9eecfe3-6a40-46d3-a1d3-d5f848af38e6
{
"url": "https://cdn.xgqfrms.xyz/logo/icon.png"
}
server.js
// const app = express();
// app.get('/image', async (req, res) => {
// const url = 'https://example.com/images/test.jpg';
// res.send(/**/); // How do I send the image binary data from the url?
// });
// const request = require('request');
// const axios = require('axios');
// const fetch = require('node-fetch');
const express = require('express');
const app = express();
app.use(function (req, res, next) {
// JSON parse
// console.log('req.body', req.body);
// fix CORS bug ✅
res.header("Access-Control-Allow-Origin", "*");
// res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// res.header("Content-Security-Policy", "connect-src *");
// res.header("Content-Security-Policy", "connect-src '*'");
// res.header("Content-Security-Policy", "connect-src 'localhost'");
// res.header("Content-Security-Policy", "connect-src localhost");
// Content-Security-Policy: connect-src <source>;
// Content-Security-Policy: connect-src <source> <source>;
// res.header('Content-Type', 'application/json');
// res.setHeader('Content-Type', 'application/json');
next();
});
// header("Access-Control-Allow-Origin: *");
app.get('/image', async (req, res) => {
const url = `https://cdn.xgqfrms.xyz/logo/icon.png`;
// res.write(url)
// res.send()
// res.send(url)
const json = {
url,
}
// ✅ 返回 JSON string
// res.header('Content-Type', 'application/json');
// res.json(JSON.stringify(json))
// 🚀 返回 JSON object
res.json(json)
// res.set('Content-Type', 'text/html');
// res.send(JSON.stringify(url));
// res.sendFile(url)
});
// app.get('/image', async (req, res) => {
// // const url = 'https://example.com/images/test.jpg';
// const url = `https://cdn.xgqfrms.xyz/logo/icon.png`;
// request({
// url: url,
// encoding: null
// },
// (err, resp, buffer) => {
// if (!err && resp.statusCode === 200){
// res.set("Content-Type", "image/jpeg");
// res.send(resp.body);
// }
// });
// });
const defaultPort = 3000;
const port = process.env.PORT || defaultPort
app.listen(port, () => {
console.log(`app is running on http://localhost:${port}`)
});
// https://cdn.xgqfrms.xyz/logo/icon.png
// http://localhost:3000/image
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="author" content="xgqfrms">
<meta name="generator" content="VS code">
<title>image</title>
</head>
<body>
<header>
<h1>image</h1>
</header>
<main>
<img id="img" data-src="http://localhost:3000/image" src="" alt="" />
</main>
<footer>
<p>copyright© xgqfrms 2022</p>
</footer>
<script>
function generatorBlobVideo(url, dom) {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function(res) {
let blob = new Blob(
[xhr.response],
{'type' : 'image/png'},
);
console.log(`blob =`, blob)
let urlBlob = URL.createObjectURL(blob);
console.log(`urlBlob =`, urlBlob)
dom.src = urlBlob;
};
xhr.send();
}
window.onload = () => {
async function test() {
const dom = document.querySelector('#img');
const url = `${dom.dataset.src}`;
const res = await fetch(url, {
// method: 'GET', // *GET, POST, PUT, DELETE, etc.
// mode: 'cors', // no-cors, *cors, same-origin
// cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
// credentials: 'same-origin',
// credentials: 'include',
// method: 'GET',
// // mode: 'no-cors',
// mode: 'cors',
// headers: {
// // 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;',
// // 'Content-Type': 'text/html',
// 'Accept': 'application/json',
// // 'Content-Type': 'application/json',
// "Access-Control-Allow-Origin": "*",
// },
}).then(res => res.json())
// }).then(res => {
// console.log(`res =`, res)
// // console.log(`text =`, res.text())
// // return res.text()
// console.log(`text =`, res.json())
// return res.json()
// })
console.log(`res`, res, typeof res)
generatorBlobVideo(res.url, dom);
};
test()
// setTimeout(() => {
// test()
// }, 3000);
}
</script>
</body>
</html>
(🐞 反爬虫测试!打击盗版⚠️)如果你看到这个信息, 说明这是一篇剽窃的文章,请访问 https://www.cnblogs.com/xgqfrms/ 查看原创文章!
blob
https://www.cnblogs.com/xgqfrms/p/16120141.html
refs
https://stackoverflow.com/questions/45696999/fetch-unexpected-end-of-input/77003350#77003350
https://stackoverflow.com/questions/60754335/how-do-i-send-image-data-from-a-url-using-express
©xgqfrms 2012-2021
www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!
原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!
本文首发于博客园,作者:xgqfrms,原文链接:https://www.cnblogs.com/xgqfrms/p/17666229.html
未经授权禁止转载,违者必究!