// ==UserScript==
// @name CDN & Server Info Displayer Enhanced (增强版CDN及服务器信息显示)
// @namespace http://tampermonkey.net/
// @version 2025.06.11.enhanced
// @description Enhanced CDN detection with accurate rules for major providers. Displays CDN provider, cache status, server info and POP locations. 增强版CDN检测,支持更多服务商,准确显示CDN提供商、缓存状态、服务器信息和节点位置。
// @author Claude (Enhanced by AI)
// @license MIT
// @match *://*/*
// @grant GM_addStyle
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// --- 配置项 ---
const config = {
initialPosition: { bottom: '15px', right: '15px' },
panelBgColor: 'rgba(44, 62, 80, 0.95)', // 增加透明度
panelTextColor: '#ffffff',
borderColor: '#3498db',
opacity: '0.9',
showDetailed: true, // 是否显示详细信息
animationDuration: '0.3s',
// 过滤配置
minWindowSize: { width: 400, height: 300 }, // 最小窗口尺寸
excludePatterns: [
// 验证码相关
/captcha/i, /recaptcha/i, /hcaptcha/i, /turnstile/i,
// 支付相关
/pay(pal|ment)/i, /checkout/i, /billing/i,
// 登录(不可用)弹窗
/login/i, /signin/i, /auth/i, /oauth/i,
// 广告相关
/ads/i, /advertisement/i, /doubleclick/i,
// 社交媒体插件
/facebook\.com\/plugins/i, /twitter\.com\/widgets/i,
// 其他小工具
/widget/i, /embed/i, /popup/i, /modal/i
]
};
// --- CDN 服务商检测规则 (修正并增强) ---
const cdnProviders = {
'Cloudflare': {
headers: ['cf-ray', 'cf-cache-status', 'cf-request-id'],
serverHeaders: ['cloudflare'],
priority: 10,
getInfo: (headers) => {
const ray = headers.get('cf-ray');
const cacheStatus = headers.get('cf-cache-status');
const datacenter = ray ? ray.slice(-3).toUpperCase() : 'N/A';
return {
provider: 'Cloudflare',
cache: cacheStatus?.toUpperCase() || 'N/A',
pop: datacenter,
extra: headers.get('cf-request-id') ? 'Request ID available' : null
};
}
},
'Alibaba Cloud CDN': {
headers: ['ali-swift-global-savetime', 'eagleid', 'x-cache-remote', 'x-swift-cachetime'],
serverHeaders: ['tengine', 'alicdn'],
priority: 9,
getInfo: (headers) => {
// 阿里云CDN的正确检测规则
const cacheRemote = headers.get('x-cache-remote');
const swiftCache = headers.get('x-swift-cachetime');
const eagleId = headers.get('eagleid');
let cacheStatus = 'N/A';
if (cacheRemote) {
cacheStatus = cacheRemote.includes('HIT') ? 'HIT' : 'MISS';
} else if (swiftCache) {
cacheStatus = 'HIT';
}
// 从EagleEye TraceId提取节点信息
let pop = 'N/A';
if (eagleId) {
const popMatch = eagleId.match(/(\w{2,3})-/);
pop = popMatch ? popMatch[1].toUpperCase() : 'N/A';
}
return {
provider: 'Alibaba Cloud CDN',
cache: cacheStatus,
pop: pop,
extra: headers.get('ali-swift-global-savetime') ? 'Global acceleration' : null
};
}
},
'Tencent Cloud CDN': {
headers: ['x-cache-lookup', 'x-nws-log-uuid', 'x-cache-remote'],
serverHeaders: ['nws', 'tencent'],
priority: 9,
getInfo: (headers) => {
const cacheLookup = headers.get('x-cache-lookup');
const cacheRemote = headers.get('x-cache-remote');
const nwsLog = headers.get('x-nws-log-uuid');
let cacheStatus = 'N/A';
if (cacheLookup) {
cacheStatus = cacheLookup.split(' ')[0].toUpperCase();
} else if (cacheRemote?.includes('HIT')) {
cacheStatus = 'HIT';
}
return {
provider: 'Tencent Cloud CDN',
cache: cacheStatus,
pop: nwsLog ? 'Available' : 'N/A',
extra: null
};
}
},
'AWS CloudFront': {
headers: ['x-amz-cf-pop', 'x-amz-cf-id', 'x-cache'],
priority: 9,
getInfo: (headers) => {
const pop = headers.get('x-amz-cf-pop');
const cache = headers.get('x-cache');
return {
provider: 'AWS CloudFront',
cache: cache?.split(' from ')[0] || 'N/A',
pop: pop || 'N/A',
extra: headers.get('x-amz-cf-id') ? 'Request ID available' : null
};
}
},
'QUIC.cloud': {
headers: ['x-qc-cache', 'x-qc-pop', 'x-litespeed-cache'],
serverHeaders: ['litespeed'],
priority: 8,
getInfo: (headers) => {
const qcCache = headers.get('x-qc-cache');
const lsCache = headers.get('x-litespeed-cache');
const pop = headers.get('x-qc-pop');
let cacheStatus = qcCache || lsCache || 'N/A';
if (cacheStatus !== 'N/A') {
cacheStatus = cacheStatus.toUpperCase();
}
return {
provider: 'QUIC.cloud',
cache: cacheStatus,
pop: pop?.toUpperCase() || 'N/A',
extra: null
};
}
},
'Fastly': {
headers: ['x-served-by', 'x-cache', 'fastly-debug-digest'],
priority: 8,
getInfo: (headers) => {
const servedBy = headers.get('x-served-by');
const cache = headers.get('x-cache');
return {
provider: 'Fastly',
cache: cache?.split(',')[0] || 'N/A',
pop: servedBy?.split('-')[0] || 'N/A',
extra: headers.get('fastly-debug-digest') ? 'Debug info available' : null
};
}
},
'KeyCDN': {
headers: ['x-edge-location', 'x-cache'],
serverHeaders: ['keycdn'],
priority: 7,
getInfo: (headers) => ({
provider: 'KeyCDN',
cache: headers.get('x-cache') || 'N/A',
pop: headers.get('x-edge-location') || 'N/A',
extra: null
})
},
'MaxCDN/StackPath': {
headers: ['x-served-by', 'x-cache'],
check: (headers) => {
const servedBy = headers.get('x-served-by');
return servedBy && servedBy.includes('maxcdn');
},
priority: 7,
getInfo: (headers) => ({
provider: 'MaxCDN/StackPath',
cache: headers.get('x-cache') || 'N/A',
pop: headers.get('x-served-by')?.split('.')[0] || 'N/A',
extra: null
})
},
'Vercel Edge Network': {
headers: ['x-vercel-id', 'x-vercel-cache'],
priority: 8,
getInfo: (headers) => {
const vercelId = headers.get('x-vercel-id');
const cache = headers.get('x-vercel-cache');
let pop = 'N/A';
if (vercelId) {
const parts = vercelId.split('::');
if (parts.length > 1) {
pop = parts[1].split('-')[0].toUpperCase();
}
}
return {
provider: 'Vercel Edge Network',
cache: cache?.toUpperCase() || 'N/A',
pop: pop,
extra: null
};
}
},
'BunnyCDN': {
headers: ['cdn-cache', 'cdn-pullzone', 'cdn-requestid'],
serverHeaders: ['bunnycdn'],
priority: 7,
getInfo: (headers) => ({
provider: 'BunnyCDN',
cache: headers.get('cdn-cache')?.toUpperCase() || 'N/A',
pop: headers.get('cdn-pullzone') || 'N/A',
extra: headers.get('cdn-requestid') ? 'Request ID available' : null
})
},
'Akamai': {
headers: ['x-akamai-transformed', 'x-check-cacheable', 'x-cache-key'],
priority: 9,
getInfo: (headers) => {
const cache = headers.get('x-check-cacheable') || headers.get('x-cache');
return {
provider: 'Akamai',
cache: cache || 'N/A',
pop: 'N/A',
extra: headers.get('x-akamai-transformed') ? 'Content transformed' : null
};
}
},
'Azure CDN': {
headers: ['x-azure-ref', 'x-cache'],
priority: 8,
getInfo: (headers) => ({
provider: 'Azure CDN',
cache: headers.get('x-cache') || 'N/A',
pop: headers.get('x-azure-ref')?.split(':')[0] || 'N/A',
extra: null
})
},
'Google Cloud CDN': {
headers: ['x-goog-generation', 'x-goog-hash', 'x-cache'],
serverHeaders: ['gws'],
priority: 8,
getInfo: (headers) => ({
provider: 'Google Cloud CDN',
cache: headers.get('x-cache') || 'N/A',
pop: 'N/A',
extra: headers.get('x-goog-generation') ? 'Object versioning' : null
})
},
'Netlify': {
headers: ['x-nf-request-id'],
serverHeaders: ['netlify'],
priority: 7,
getInfo: (headers) => ({
provider: 'Netlify Edge',
cache: 'N/A',
pop: 'N/A',
extra: 'Netlify Edge Network'
})
},
'jsDelivr': {
headers: ['x-served-by'],
check: (headers) => {
const servedBy = headers.get('x-served-by');
return servedBy && servedBy.includes('jsdelivr');
},
priority: 6,
getInfo: (headers) => ({
provider: 'jsDelivr CDN',
cache: 'N/A',
pop: headers.get('x-served-by')?.split('-')[0] || 'N/A',
extra: 'Open Source CDN'
})
}
};
/**
* 从headers中解析CDN或服务器信息
*/
function parseInfo(headers) {
const lowerCaseHeaders = new Map();
for (const [key, value] of headers.entries()) {
lowerCaseHeaders.set(key.toLowerCase(), value);
}
let detectedProviders = [];
// 检测所有匹配的CDN提供商
for (const [cdnName, cdn] of Object.entries(cdnProviders)) {
let isMatch = false;
// 检查特定的头部字段
if (cdn.headers?.some(header => lowerCaseHeaders.has(header.toLowerCase()))) {
isMatch = true;
}
// 检查服务器头部
if (cdn.serverHeaders) {
const serverHeader = lowerCaseHeaders.get('server') || '';
if (cdn.serverHeaders.some(server =>
serverHeader.toLowerCase().includes(server.toLowerCase()))) {
isMatch = true;
}
}
// 自定义检查函数
if (cdn.check && cdn.check(lowerCaseHeaders)) {
isMatch = true;
}
if (isMatch) {
const info = cdn.getInfo(lowerCaseHeaders);
detectedProviders.push({
...info,
priority: cdn.priority || 5
});
}
}
// 如果检测到多个CDN,选择优先级最高的
if (detectedProviders.length > 0) {
detectedProviders.sort((a, b) => b.priority - a.priority);
return detectedProviders[0];
}
// 如果没有匹配到已知CDN,尝试显示服务器信息
const server = lowerCaseHeaders.get('server');
const xCache = lowerCaseHeaders.get('x-cache');
const via = lowerCaseHeaders.get('via');
if (server || xCache || via) {
return {
provider: server || 'Unknown Server',
cache: xCache?.split(' ')[0] || 'N/A',
pop: via ? 'Proxy detected' : 'N/A',
extra: via ? `Via: ${via}` : null
};
}
return {
provider: 'Direct Connection',
cache: 'N/A',
pop: 'N/A',
extra: 'No CDN detected'
};
}
/**
* 创建样式
*/
function addStyles() {
GM_addStyle(`
#cdn-info-panel-enhanced {
position: fixed;
z-index: 99999;
padding: 12px 16px;
border-radius: 12px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 13px;
color: ${config.panelTextColor};
background: ${config.panelBgColor};
backdrop-filter: blur(10px);
border: 1px solid ${config.borderColor};
box-shadow: 0 8px 32px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.1);
cursor: move;
user-select: none;
transition: opacity ${config.animationDuration}, transform ${config.animationDuration};
opacity: ${config.opacity};
transform: scale(1);
min-width: 200px;
}
#cdn-info-panel-enhanced:hover {
opacity: 1;
transform: scale(1.02);
}
#cdn-info-panel-enhanced .panel-header {
font-weight: 600;
font-size: 14px;
margin-bottom: 8px;
color: ${config.borderColor};
text-align: center;
border-bottom: 1px solid rgba(52, 152, 219, 0.3);
padding-bottom: 6px;
}
#cdn-info-panel-enhanced .info-line {
display: flex;
justify-content: space-between;
align-items: center;
margin: 6px 0;
padding: 2px 0;
}
#cdn-info-panel-enhanced .info-label {
font-weight: 500;
color: #a9cce3;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
#cdn-info-panel-enhanced .info-value {
font-weight: 600;
color: #ffffff;
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: right;
}
#cdn-info-panel-enhanced .extra-info {
font-size: 11px;
color: #95a5a6;
font-style: italic;
text-align: center;
margin-top: 8px;
padding-top: 6px;
border-top: 1px solid rgba(149, 165, 166, 0.2);
}
#cdn-info-panel-enhanced .cache-hit {
color: #2ecc71 !important;
}
#cdn-info-panel-enhanced .cache-miss {
color: #e74c3c !important;
}
#cdn-info-panel-enhanced .close-btn {
position: absolute;
top: -8px;
right: -8px;
width: 20px;
height: 20px;
border-radius: 50%;
background: #e74c3c;
color: white;
border: none;
cursor: pointer;
font-size: 12px;
display: none;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
#cdn-info-panel-enhanced:hover .close-btn {
display: flex;
}
#cdn-info-panel-enhanced .close-btn:hover {
background: #c0392b;
transform: scale(1.1);
}
`);
}
/**
* 创建并显示信息面板
*/
function createDisplayPanel(info) {
if (!info || document.getElementById('cdn-info-panel-enhanced')) return;
addStyles();
const panel = document.createElement('div');
panel.id = 'cdn-info-panel-enhanced';
// 根据缓存状态添加样式类
let cacheClass = '';
if (info.cache.toLowerCase().includes('hit')) {
cacheClass = 'cache-hit';
} else if (info.cache.toLowerCase().includes('miss')) {
cacheClass = 'cache-miss';
}
const providerLabel = info.provider.includes('CDN') ||
info.provider.includes('Cloud') ||
info.provider.includes('Edge') ? 'CDN' : 'Server';
panel.innerHTML = `
<button class="close-btn" onclick="this.parentElement.remove()">×</button>
<div class="panel-header">CDN Detector</div>
<div class="info-line">
<span class="info-label">${providerLabel}</span>
<span class="info-value" title="${info.provider}">${info.provider}</span>
</div>
<div class="info-line">
<span class="info-label">Cache</span>
<span class="info-value ${cacheClass}">${info.cache}</span>
</div>
<div class="info-line">
<span class="info-label">POP</span>
<span class="info-value">${info.pop}</span>
</div>
${info.extra ? `<div class="extra-info">${info.extra}</div>` : ''}
`;
// 设置初始位置
Object.assign(panel.style, config.initialPosition);
document.body.appendChild(panel);
// 使面板可拖拽
makeDraggable(panel);
// 添加入场动画
requestAnimationFrame(() => {
panel.style.opacity = config.opacity;
});
}
/**
* 使元素可拖拽
*/
function makeDraggable(element) {
let isDragging = false;
let startX = 0, startY = 0;
let elementX = 0, elementY = 0;
element.addEventListener('mousedown', dragStart, false);
document.addEventListener('mousemove', drag, false);
document.addEventListener('mouseup', dragEnd, false);
function dragStart(e) {
if (e.target.classList.contains('close-btn')) return;
e.preventDefault();
isDragging = true;
// 记录鼠标起始位置
startX = e.clientX;
startY = e.clientY;
// 获取元素当前位置
const rect = element.getBoundingClientRect();
elementX = rect.left;
elementY = rect.top;
// 移除过渡效果,确保拖拽流畅
element.style.transition = 'none';
// 添加拖拽时的视觉反馈
element.style.opacity = '1';
element.style.transform = 'scale(1.05)';
}
function drag(e) {
if (!isDragging) return;
e.preventDefault();
// 计算鼠标移动的距离
const deltaX = e.clientX - startX;
const deltaY = e.clientY - startY;
// 计算元素新位置
const newX = elementX + deltaX;
const newY = elementY + deltaY;
// 边界检测,防止拖出屏幕
const maxX = window.innerWidth - element.offsetWidth;
const maxY = window.innerHeight - element.offsetHeight;
const finalX = Math.max(0, Math.min(newX, maxX));
const finalY = Math.max(0, Math.min(newY, maxY));
// 更新元素位置
element.style.position = 'fixed';
element.style.left = finalX + 'px';
element.style.top = finalY + 'px';
element.style.right = 'auto';
element.style.bottom = 'auto';
element.style.transform = 'scale(1.05)';
}
function dragEnd() {
if (!isDragging) return;
isDragging = false;
// 恢复过渡效果和正常状态
element.style.transition = `opacity ${config.animationDuration}, transform ${config.animationDuration}`;
element.style.transform = 'scale(1)';
element.style.opacity = config.opacity;
}
}
/**
* 检查是否应该显示CDN检测面板
*/
function shouldShowPanel() {
// 1. 检查是否在iframe中
if (window !== window.top) {
console.log('[CDN Detector] Running in iframe, checking if should display...');
// 获取iframe尺寸
const frameWidth = window.innerWidth;
const frameHeight = window.innerHeight;
// iframe太小则不显示
if (frameWidth < config.minWindowSize.width || frameHeight < config.minWindowSize.height) {
console.log(`[CDN Detector] Iframe too small (${frameWidth}x${frameHeight}), skipping display`);
return false;
}
// 检查iframe的URL是否匹配排除模式
const currentUrl = window.location.href.toLowerCase();
for (const pattern of config.excludePatterns) {
if (pattern.test(currentUrl)) {
console.log(`[CDN Detector] URL matches exclude pattern: ${pattern}, skipping display`);
return false;
}
}
// 检查父页面信息(如果可访问)
try {
const parentUrl = window.parent.location.href.toLowerCase();
for (const pattern of config.excludePatterns) {
if (pattern.test(parentUrl)) {
console.log(`[CDN Detector] Parent URL matches exclude pattern: ${pattern}, skipping display`);
return false;
}
}
} catch (e) {
// 跨域限制,无法访问父页面信息,这很常见
console.log('[CDN Detector] Cannot access parent frame info (CORS), continuing...');
}
}
// 2. 检查当前页面URL
const currentUrl = window.location.href.toLowerCase();
for (const pattern of config.excludePatterns) {
if (pattern.test(currentUrl)) {
console.log(`[CDN Detector] Current URL matches exclude pattern: ${pattern}, skipping display`);
return false;
}
}
// 3. 检查页面标题
const pageTitle = document.title.toLowerCase();
const titleExcludePatterns = [
/captcha/i, /verify/i, /challenge/i, /security check/i,
/human verification/i, /robot check/i
];
for (const pattern of titleExcludePatterns) {
if (pattern.test(pageTitle)) {
console.log(`[CDN Detector] Page title matches exclude pattern: ${pattern}, skipping display`);
return false;
}
}
// 4. 检查常见的验证码容器元素
const captchaSelectors = [
'[id*="captcha"]', '[class*="captcha"]',
'[id*="recaptcha"]', '[class*="recaptcha"]',
'[id*="hcaptcha"]', '[class*="hcaptcha"]',
'[class*="cf-turnstile"]', '[id*="turnstile"]'
];
for (const selector of captchaSelectors) {
if (document.querySelector(selector)) {
console.log(`[CDN Detector] Found captcha element: ${selector}, skipping display`);
return false;
}
}
// 5. 检查窗口尺寸(对于主窗口)
if (window === window.top) {
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
if (windowWidth < config.minWindowSize.width || windowHeight < config.minWindowSize.height) {
console.log(`[CDN Detector] Main window too small (${windowWidth}x${windowHeight}), skipping display`);
return false;
}
}
// 6. 检查特殊的域名
const hostname = window.location.hostname.toLowerCase();
const excludeDomains = [
'accounts.google.com',
'login.microsoftonline.com',
'auth0.com',
'okta.com',
'captcha.com',
'recaptcha.net',
'hcaptcha.com',
'challenges.cloudflare.com'
];
for (const domain of excludeDomains) {
if (hostname.includes(domain)) {
console.log(`[CDN Detector] Excluded domain detected: ${domain}, skipping display`);
return false;
}
}
console.log('[CDN Detector] All checks passed, panel will be displayed');
return true;
}
async function main() {
// 等待页面完全加载
if (document.readyState !== "complete") {
return new Promise(resolve => {
window.addEventListener("load", () => {
main().then(resolve);
});
});
}
try {
console.log('[CDN Detector] Starting detection...');
// 尝试获取当前页面的响应头
const response = await fetch(window.location.href, {
method: 'HEAD', // 使用HEAD请求减少数据传输
cache: 'no-cache',
redirect: 'follow'
});
const info = parseInfo(response.headers);
console.log('[CDN Detector] Detection result:', info);
createDisplayPanel(info);
} catch (error) {
console.warn('[CDN Detector] Failed to fetch headers:', error.message);
// 降级处理:显示基于已知信息的检测结果
createDisplayPanel({
provider: 'Detection Limited',
cache: 'N/A',
pop: 'N/A',
extra: 'CORS policy blocking header access'
});
}
}
// 启动脚本
main().catch(error => {
console.error('[CDN Detector] Initialization failed:', error);
});
})();