利用 CF Workers 反代官方 telegra.ph 实现无需 PHP 空间,单个首页文件 index.html 就能完成整个站点。
官方github地址:https://github.com/missuo/Telegraph-Image-Hosting
1、在cloudflare上部署worker,代码填写如下
async function handleRequest(request) {
const { origin, pathname, searchParams } = new URL(request.url);
const param = searchParams.toString() ? "?" + searchParams.toString() : "";
const requestHeaders = request.headers.get("Access-Control-Request-Headers");
const requestMethod = request.headers.get("Access-Control-Request-Method");
const requestOrigin = request.headers.get("Origin") ? request.headers.get("Origin") : origin;
// 响应预检请求
if (request.method == "OPTIONS") {
return new Response('{"Access": "OPTIONS"}', {
status: 200,
headers: {
"Access-Control-Allow-Origin": requestOrigin ? requestOrigin : "*", //不限制请求来源
//"Access-Control-Allow-Origin": "https://yunimg.cc", //限制 CROS 域名,上下两个都要改你自己的
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers": requestHeaders ? requestHeaders : "*",
"Access-Control-Allow-Methods": requestMethod ? requestMethod : "*",
"Content-Type": "application/json",
}
});
}
// 处理正式请求
const newRequest = new Request("https://telegra.ph/upload" + pathname + param, request);
// 请求头删除来源
newRequest.headers.set("referrer-policy", "no-referrer");
newRequest.headers.delete("Referer");
newRequest.headers.delete("Origin");
// 发起请求
const response = await fetch(newRequest);
const newResponse = new Response(response.body, response);
// 处理响应
newResponse.headers.set("Access-Control-Allow-Origin", requestOrigin ? requestOrigin : "*");
//newResponse.headers.set("Access-Control-Allow-Origin", "https://yunimg.cc"); //限制 CROS 域名,上下两个都要改你自己的
newResponse.headers.set("Access-Control-Allow-Credentials", "true");
newResponse.headers.set("Access-Control-Allow-Headers", requestHeaders ? requestHeaders : "*");
newResponse.headers.set("Access-Control-Allow-Methods", requestMethod ? requestMethod : "*");
newResponse.headers.set('Access-Control-Expose-Headers', '*');
newResponse.headers.set("Content-Type", "application/json");
return newResponse;
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
})
2、创建域名路由指向上边部署的worker。
3、创建一个index.html,填入如下代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电报图床 - 电报图像托管,免费和无限的图像托管</title>
<meta name="description" content="基于 Telegraph 免费和无限的图像托管">
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.4.1/css/bootstrap.min.css">
<style>
body {
font-family: Arial, sans-serif;
background:#f6f8fa url(./bg.png) top;
}
.container {
max-width: 600px;
margin: 35px auto;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0,0,0,0.2);
background-color: rgba(246,248,250,0.5);
}
.upload-btn-wrapper {
position: relative;
justify-content: center;
align-items: center;
overflow: hidden;
display: flex;
background-color: #007BFF;
color: #FFF;
border-radius: 5px;
padding: 10px;
cursor: pointer;
transition: background-color 0.3s;
}
.upload-btn-wrapper:hover {
background-color: #0056b3;
}
.upload-btn-wrapper input[type=file] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
.custom-input-group-append {
position: relative;
overflow: hidden;
display: flex;
}
.alert {
position: fixed;
z-index: 9999;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0.6;
padding: 10px;
}
.alert.alert-warning {
color: #fff;
background-color: #333333;
border: 1px solid #ddd;
border-radius: 2px;
}
</style>
</head>
<body>
<div class="container">
<h2 class="text-center">电报图像托管</h2>
<p class="text-center text-muted" style="color:red;">免费和无限的图像托管</p>
<p class="text-center text-muted" style="color:#A569BD;">立即开始上传您的图片,上传图片限制 5M 以内</p>
<hr>
<div class="upload-btn-wrapper text-center">
<span>选择图片</span>
<input type="file" name="file" id="fileInput" accept="image/png, image/jpeg, image/jpg, image/gif">
</div>
<div id="uploadStatus" style="margin-top: 20px;"></div>
<hr>
<p align="center">© <script>document.write(new Date().getFullYear())</script> <a href="https://img.yunloc.com" target="_Blank">Yunloc</a> Image. Author <a href="https://t.me/missuo" target="_Blank">Vincent</a>, <a href="https://www.yunloc.com/1738.html" target="_Blank">[ Install Help ]</a></p>
</div>
<script>
const fileInput = document.getElementById('fileInput');
const uploadStatus = document.getElementById('uploadStatus');
fileInput.addEventListener('change', function() {
const file = fileInput.files[0];
if (file) {
uploadImage(file);
}
});
function uploadImage(file) {
const formData = new FormData();
formData.append('file', file);
uploadStatus.innerHTML = '<div class="alert alert-info"><i class="glyphicon glyphicon-upload"></i> 上传中,请稍候...</div>';
fetch('//missuo.ru/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
const src = 'https://这里填写图片地址' + data[0].src;
const src1 = 'https://i1.wp.com/这里是图片地址2' + data[0].src;
const src2 = 'https://i3.wp.com/telegra.ph' + data[0].src;
uploadStatus.innerHTML = `
<div class="alert alert-success"><i class="glyphicon glyphicon-ok"></i> 上传成功!</div>
<div class="text-center">
<img src="${src}" class="img-fluid mb-3" alt="Uploaded Image" style="max-width: 100%;">
</div>
<div class="input-group">
<input type="text" class="form-control" style="margin-top: 20px;" id="imageUrl" value="${src}">
<div class="custom-input-group-append" style="margin-top: 60px;">
<a href="${src}" target="_blank"><button type="button" class="btn btn-primary">在新标签中打开</button></a>
<button class="btn btn-primary" type="button" onclick="copyImageUrl('imageUrl')" style="margin-left: 5px;">复制网址</button>
</div>
</div>
<div class="input-group">
<input type="text" class="form-control" style="margin-top: 20px;" id="imageUrl1" value="${src1}">
<div class="custom-input-group-append" style="margin-top: 60px;">
<a href="${src1}" target="_blank"><button type="button" class="btn btn-primary">在新标签中打开</button></a>
<button class="btn btn-primary" type="button" onclick="copyImageUrl('imageUrl1')" style="margin-left: 5px;">复制网址</button>
</div>
</div>
<div class="input-group">
<input type="text" class="form-control" style="margin-top: 20px;" id="imageUrl2" value="${src2}">
<div class="custom-input-group-append" style="margin-top: 60px;">
<a href="${src2}" target="_blank"><button type="button" class="btn btn-primary">在新标签中打开</button></a>
<button class="btn btn-primary" type="button" onclick="copyImageUrl('imageUrl2')" style="margin-left: 5px;">复制网址</button>
</div>
</div>
`;
setTimeout(function() {
const successAlert = document.querySelector('.alert-success');
successAlert.style.display = 'none';
}, 5000);
})
.catch(error => {
uploadStatus.innerHTML = '<div class="alert alert-danger"><i class="glyphicon glyphicon-remove"></i> 上传失败! 请再试一次...</div>';
});
}
function copyImageUrl(imageUrlId) {
const imageUrl = document.getElementById(imageUrlId).value;
navigator.clipboard.writeText(imageUrl)
.then(function() {
const alertBox = document.createElement('div');
alertBox.className = 'alert alert-warning';
alertBox.innerHTML = '<i class="glyphicon glyphicon-info-sign"></i> 已复制到剪贴板!';
document.body.appendChild(alertBox);
setTimeout(function() {
alertBox.remove();
}, 2000);
})
.catch(function(error) {
console.error('复制失败:', error);
});
}
</script>
</body>
</html>
将第100行处填写cloudflare worker的telegraph代理的项目地址。
4、上传至服务器或者对象存储服务,例如阿里云的oss之类,并指定域名。
访问域名即可开始使用图床服务。