Skip to content

Instantly share code, notes, and snippets.

@wyf9
Last active December 3, 2025 01:48
Show Gist options
  • Select an option

  • Save wyf9/beeb6746fa7fda73f78380cbdda5461e to your computer and use it in GitHub Desktop.

Select an option

Save wyf9/beeb6746fa7fda73f78380cbdda5461e to your computer and use it in GitHub Desktop.
CF Snippet GetIP API

一个简单的 Cloudflare Snippet 获取访问者 IP & 归属地 API 脚本

Try it: https://ip.siiway.top

Important

Clash <-> Sharelink 转换功能已拆分为单独的仓库: siiway/urlclash-converter

路由

  • / -> 根目录 (根据访问客户端自动选择 HTML / 纯文本)
  • /json -> 返回 JSON 格式的数据
  • /txt -> 返回纯文本格式的数据
  • /html -> 返回网页格式的数据
  • /ip -> 只返回访问者 IP,不带任何格式 / 说明
  • /full -> 以 JSON 格式返回脚本获取到的所有信息 (IP, 归属地, Headers, Security, ...)

自行部署

请确保设置片段规则为 自定义筛选表达式

  • 字段: 主机名
  • 运算符: 等于
  • 值: 你想要的域名

切勿选择 所有传入请求, 否则会导致你整个网站的流量被路由到 worker!

Example:

image
function isBrowserUA(request) {
const userAgent = request.headers.get('User-Agent') || '';
const acceptHeader = request.headers.get('Accept') || '';
const prefersHtml = acceptHeader.includes('text/html');
const browserPatterns = [
'mozilla',
'chrome',
'safari',
'firefox',
'edge',
'opera',
'ucbrowser',
'samsungbrowser',
];
const nonBrowserPatterns = [
'curl',
'wget',
'httpie',
'postman',
'python-requests',
'bot',
'spider',
'crawler',
];
const isBrowserAgent = browserPatterns.some(pattern => userAgent.toLowerCase().includes(pattern));
const isNonBrowserAgent = nonBrowserPatterns.some(pattern => userAgent.toLowerCase().includes(pattern));
return prefersHtml || (isBrowserAgent && !isNonBrowserAgent);
}
async function process_json(request) {
let data = {
ip: request.headers.get('CF-Connecting-IP') || null,
cf: {
continent: request.cf?.continent || null,
country: request.cf?.country || null,
isEUCountry: request.cf?.isEUCountry || false,
region: request.cf?.region || null,
regionCode: request.cf?.regionCode || null,
city: request.cf?.city || null,
latitude: request.cf?.latitude || null,
longitude: request.cf?.longitude || null,
postalCode: request.cf?.postalCode || null,
metroCode: request.cf?.metroCode || null,
colo: request.cf?.colo || null,
asn: request.cf?.asn || null,
asOrganization: request.cf?.asOrganization || null,
timezone: request.cf?.timezone || null,
},
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
};
const dataJson = JSON.stringify(data, null, 4);
return new Response(dataJson, {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
});
}
async function process_txt(request) {
let data = {
ip: request.headers.get('CF-Connecting-IP') || null,
cf: {
continent: request.cf?.continent || null,
country: request.cf?.country || null,
region: request.cf?.region || null,
city: request.cf?.city || null,
colo: request.cf?.colo || null,
asn: request.cf?.asn || null,
asOrganization: request.cf?.asOrganization || null,
},
};
const text = `IP: ${data.ip || 'N/A'}\n` +
`Continent: ${data.cf.continent || 'N/A'}\n` +
`Country: ${data.cf.country || 'N/A'}\n` +
`Region: ${data.cf.region || 'N/A'}\n` +
`City: ${data.cf.city || 'N/A'}\n` +
`Colo: ${data.cf.colo || 'N/A'}\n` +
`ASN: ${data.cf.asn || 'N/A'}\n` +
`ASOrganization: ${data.cf.asOrganization || 'N/A'}\n` +
`Source: https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e\n`;
return new Response(text, {
headers: {
'Content-Type': 'text/plain;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
});
}
async function process_html(request) {
let data = {
ip: request.headers.get('CF-Connecting-IP') || null,
cf: {
continent: request.cf?.continent || null,
country: request.cf?.country || null,
region: request.cf?.region || null,
city: request.cf?.city || null,
colo: request.cf?.colo || null,
asn: request.cf?.asn || null,
asOrganization: request.cf?.asOrganization || null,
},
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
};
const info = [];
if (data.ip) info.push(`<strong>IP:</strong> ${data.ip}`);
if (data.cf.continent) info.push(`<strong>大陆 | Continent:</strong> ${data.cf.continent}`);
if (data.cf.country) info.push(`<strong>国家 | Country:</strong> ${data.cf.country}`);
if (data.cf.region) info.push(`<strong>地区 | Region:</strong> ${data.cf.region}`);
if (data.cf.city) info.push(`<strong>城市 | City:</strong> ${data.cf.city}`);
if (data.cf.colo) info.push(`<strong>数据中心 | Colo:</strong> ${data.cf.colo}`);
if (data.cf.asn) info.push(`<strong>ASN:</strong> ${data.cf.asn}`);
if (data.cf.asOrganization) info.push(`<strong>AS 组织 | AS Organization:</strong> ${data.cf.asOrganization}`);
const visitorInfo = info.length > 0 ? info.join('<br/><br/>') : '没有可用的访客信息 | No visitor information available.';
const html = `
<!DOCTYPE html>
<html>
<head>
<title>IP 信息 | IP Information</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
max-width: 800px;
margin: 0 auto;
background: var(--bg-color);
color: var(--text-color);
}
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #1a1a1a;
--text-color: #e0e0e0;
--pre-bg: #2a2a2a;
}
}
@media (prefers-color-scheme: light) {
:root {
--bg-color: #ffffff;
--text-color: #333333;
--pre-bg: #f4f4f4;
}
}
h1 { font-size: 24px; }
.info { margin-bottom: 20px; }
pre {
background: var(--pre-bg);
padding: 10px;
border-radius: 5px;
overflow-x: auto;
}
a { color: var(--text-color); }
.source { font-size: 14px; margin-top: 20px; }
</style>
</head>
<body>
<h1>您的 IP 信息 | Your IP Information</h1>
<div class="info">${visitorInfo}</div>
<h2>原始数据 | Raw Data</h2>
<pre>${JSON.stringify(data, null, 2)}</pre>
<p class="source">源代码 | Source: <a href="${data.source}">${data.source}</a></p>
</body>
</html>
`;
return new Response(html, {
headers: {
'Content-Type': 'text/html;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
});
}
async function process_root(request) {
return isBrowserUA(request) ? process_html(request) : process_txt(request);
}
async function process_full(request, url) {
let data = {
method: request.method,
url: request.url,
origin: url.origin,
ip: request.headers.get('CF-Connecting-IP') || null,
cf: {
continent: request.cf?.continent || null,
country: request.cf?.country || null,
isEUCountry: request.cf?.isEUCountry || false,
region: request.cf?.region || null,
regionCode: request.cf?.regionCode || null,
city: request.cf?.city || null,
latitude: request.cf?.latitude || null,
longitude: request.cf?.longitude || null,
postalCode: request.cf?.postalCode || null,
metroCode: request.cf?.metroCode || null,
colo: request.cf?.colo || null,
asn: request.cf?.asn || null,
asOrganization: request.cf?.asOrganization || null,
timezone: request.cf?.timezone || null,
},
headers: {},
security: {},
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
};
// Populate Headers
request.headers.forEach((value, name) => {
data.headers[name] = value;
});
// Populate Security fields
const securityKeys = [
'clientTcpRtt',
'tlsCipher',
'tlsVersion',
'httpProtocol',
'clientHandshake',
'clientFinished',
'serverHandshake',
'serverFinished',
'corporateProxy',
'verifiedBot',
'score',
];
if (request.cf) {
for (const key of securityKeys) {
if (request.cf[key]) {
if (typeof request.cf[key] === 'object') {
for (const innerKey in request.cf[key]) {
data.security[innerKey] = request.cf[key][innerKey];
}
} else {
data.security[key] = request.cf[key];
}
}
}
}
const dataJson = JSON.stringify(data, null, 4);
return new Response(dataJson, {
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
});
}
export default {
async fetch(request) {
const url = new URL(request.url);
switch (url.pathname) {
case '/ip':
case '/.ip':
return new Response(request.headers.get('CF-Connecting-IP') || 'N/A', {
headers: {
'Content-Type': 'text/plain;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
});
case '/json':
case '/.json':
return await process_json(request);
case '/':
return await process_root(request);
case '/txt':
case '/.txt':
return await process_txt(request);
case '/html':
case '/.html':
return await process_html(request);
case '/full':
case '/.full':
return await process_full(request, url);
default:
return new Response(
JSON.stringify(
{
usage: {
'/ip': '返回纯 IP | Return only IP',
'/json': '返回 JSON 数据 (仅 IP 和位置信息) | Return JSON data (IP and location only)',
'/full': '返回完整数据 (包括头部和安全信息) | Return FULL data (includes headers & security)',
'/txt': '返回纯文本数据 (IP 和位置信息) | Return plain text data (IP and location)',
'/html': '返回 HTML 页面 (IP 和位置信息) | Return HTML with IP and location data',
},
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
null,
4
),
{
status: 404,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e',
},
}
);
}
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment