匿名用户版本:
// Docker Hub 的官方 Registry 地址
const DOCKER_HUB_REGISTRY = "registry-1.docker.io";
// 用于解析 Docker Hub 认证服务的地址
const DOCKER_HUB_AUTH_SERVICE = "auth.docker.io";
// 处理请求的主函数
async function handleRequest(request) {
const url = new URL(request.url);
// 1. 处理 /v2/ 的请求,这是所有操作的入口
// 例如: GET /v2/ 或 GET /v2/library/nginx/manifests/latest
if (url.pathname.startsWith('/v2/')) {
// 修改请求的 Host 和目标 URL,将其指向 Docker Hub
const newUrl = new URL(url.pathname + url.search, `https://${DOCKER_HUB_REGISTRY}`);
// 创建一个新的请求,复制原始请求的 Method、Headers 和 Body
const newRequest = new Request(newUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'manual', // 手动处理重定向,对于认证很重要
});
// 发送请求到 Docker Hub
const response = await fetch(newRequest);
// 2. 处理 401 Unauthorized 响应
// 当 Docker Hub 需要认证时,会返回 401 和一个 WWW-Authenticate 头
if (response.status === 401) {
const authHeader = response.headers.get('WWW-Authenticate');
if (authHeader && authHeader.startsWith('Bearer ')) {
// 从 WWW-Authenticate 头中解析出认证参数
const params = parseAuthParams(authHeader);
// 构建获取 Token 的 URL
const tokenUrl = new URL(`https://${DOCKER_HUB_AUTH_SERVICE}/token`);
tokenUrl.searchParams.set('service', params.service);
tokenUrl.searchParams.set('scope', params.scope);
// 请求 Token
const tokenResponse = await fetch(tokenUrl);
if (!tokenResponse.ok) {
return new Response('Failed to get auth token', { status: 502 });
}
const { token } = await tokenResponse.json();
// 使用获取到的 Token 重新发送原始请求
const authedRequest = new Request(newRequest);
authedRequest.headers.set('Authorization', `Bearer ${token}`);
const authedResponse = await fetch(authedRequest);
// 返回带有 CORS 头的最终响应,允许 Docker 客户端跨域访问
return addCorsHeaders(authedResponse);
}
}
// 3. 处理 307/308 临时重定向
// Docker Hub 在某些情况下(如获取 manifest)会返回重定向
if (response.status === 307 || response.status === 308) {
const location = response.headers.get('Location');
if (location) {
// 递归调用自己来处理重定向,确保所有请求都经过我们的代理
const redirectResponse = await fetch(new URL(location, request.url), {
method: request.method,
headers: request.headers,
body: request.body,
});
return addCorsHeaders(redirectResponse);
}
}
// 4. 对于其他所有成功或失败的响应,直接返回
return addCorsHeaders(response);
}
// 如果请求不是 /v2/ 开头,返回一个简单的提示页面
return new Response(`This is a Docker registry proxy. Please use it in your Docker daemon configuration.\n\nYour request path: ${url.pathname}`, {
status: 400,
headers: { 'Content-Type': 'text/plain' }
});
}
// 辅助函数:解析 WWW-Authenticate 头中的参数
function parseAuthParams(authHeader) {
const paramsStr = authHeader.substring('Bearer '.length);
const params = {};
paramsStr.split(',').forEach(pair => {
const [key, value] = pair.trim().split('=');
params[key] = value.replace(/"/g, '');
});
return params;
}
// 辅助函数:为响应添加 CORS 头
function addCorsHeaders(response) {
const newResponse = new Response(response.body, response);
newResponse.headers.set('Access-Control-Allow-Origin', '*');
newResponse.headers.set('Access-Control-Allow-Methods', 'GET, HEAD, POST, PUT, DELETE, OPTIONS');
newResponse.headers.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, User-Agent');
return newResponse;
}
// ESA 边缘函数的入口点
export default {
async fetch(request) {
return handleRequest(request);
}
};
登陆用户版本:
// Docker Hub 的官方 Registry 地址
const DOCKER_HUB_REGISTRY = "registry-1.docker.io";
// !!! 在这里填入你刚刚生成的 Docker Hub Access Token !!!
const DOCKER_HUB_TOKEN = "你的Docker Hub Token"; // 例如: dckr_pat_xxxxxxxxxxxx
// 处理请求的主函数
async function handleRequest(request) {
const url = new URL(request.url);
// 只处理 /v2/ 路径下的请求
if (url.pathname.startsWith('/v2/')) {
// 构造新的 URL,目标指向 Docker Hub
const newUrl = `https://${DOCKER_HUB_REGISTRY}${url.pathname}${url.search}`;
// 复制原始请求的头
const newHeaders = new Headers(request.headers);
// 智能认证:
// 如果原始请求没有 Authorization 头,我们就自动加上我们的 Token
if (!newHeaders.has('Authorization')) {
newHeaders.set('Authorization', `Bearer ${DOCKER_HUB_TOKEN}`);
}
// 创建一个新的请求,使用修改后的头
const newRequest = new Request(newUrl, {
method: request.method,
headers: newHeaders,
body: request.body,
redirect: 'follow',
});
try {
const response = await fetch(newRequest);
return addCorsHeaders(response);
} catch (e) {
return new Response(`Proxy fetch error: ${e.message}`, { status: 502 });
}
}
return new Response(`This is a Docker registry proxy. Please use it in your Docker daemon configuration.\n\nYour request path: ${url.pathname}`, {
status: 400,
headers: { 'Content-Type': 'text/plain' }
});
}
// 辅助函数:为响应添加 CORS 头
function addCorsHeaders(response) {
const newResponse = new Response(response.body, response);
newResponse.headers.set('Access-Control-Allow-Origin', '*');
newResponse.headers.set('Access-Control-Allow-Methods', 'GET, HEAD, POST, PUT, DELETE, OPTIONS');
newResponse.headers.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, User-Agent');
return newResponse;
}
// ESA 边缘函数的入口点
export default {
async fetch(request) {
return handleRequest(request);
}
};