110 lines
3.7 KiB
Plaintext
110 lines
3.7 KiB
Plaintext
/**
|
||
* 导入Deno标准库中的HTTP服务器模块
|
||
*/
|
||
import { serve } from "https://deno.land/std/http/server.ts";
|
||
|
||
/**
|
||
* API映射表,定义了路由前缀到实际API端点的映射关系
|
||
* 用于将请求转发到相应的第三方服务
|
||
*/
|
||
const apiMapping = {
|
||
'/discord': 'https://discord.com/api', // Discord API
|
||
'/telegram': 'https://api.telegram.org', // Telegram API
|
||
'/openai': 'https://api.openai.com', // OpenAI API
|
||
'/claude': 'https://api.anthropic.com', // Anthropic Claude API
|
||
'/gemini': 'https://generativelanguage.googleapis.com', // Google Gemini API
|
||
'/meta': 'https://www.meta.ai/api', // Meta AI API
|
||
'/groq': 'https://api.groq.com/openai', // Groq API (OpenAI兼容)
|
||
'/xai': 'https://api.x.ai', // X.AI API
|
||
'/cohere': 'https://api.cohere.ai', // Cohere API
|
||
'/huggingface': 'https://api-inference.huggingface.co', // Hugging Face API
|
||
'/together': 'https://api.together.xyz', // Together AI API
|
||
'/novita': 'https://api.novita.ai', // Novita AI API
|
||
'/portkey': 'https://api.portkey.ai', // Portkey API
|
||
'/fireworks': 'https://api.fireworks.ai', // Fireworks AI API
|
||
'/openrouter': 'https://openrouter.ai/api' // OpenRouter API
|
||
};
|
||
|
||
/**
|
||
* 启动HTTP服务器,处理所有传入的请求
|
||
*/
|
||
serve(async (request) => {
|
||
// 解析请求URL
|
||
const url = new URL(request.url);
|
||
const pathname = url.pathname;
|
||
|
||
// 处理根路径和index.html请求
|
||
if (pathname === '/' || pathname === '/index.html') {
|
||
return new Response('Service is running!', {
|
||
status: 200,
|
||
headers: { 'Content-Type': 'text/html' }
|
||
});
|
||
}
|
||
|
||
// 处理robots.txt请求,禁止搜索引擎爬取
|
||
if (pathname === '/robots.txt') {
|
||
return new Response('User-agent: *\nDisallow: /', {
|
||
status: 200,
|
||
headers: { 'Content-Type': 'text/plain' }
|
||
});
|
||
}
|
||
|
||
// 从请求路径中提取API前缀和剩余路径
|
||
const [prefix, rest] = extractPrefixAndRest(pathname, Object.keys(apiMapping));
|
||
if (!prefix) {
|
||
return new Response('Not Found', { status: 404 });
|
||
}
|
||
|
||
// 构建目标URL
|
||
const targetUrl = `${apiMapping[prefix]}${rest}`;
|
||
|
||
try {
|
||
// 创建新的请求头,只保留允许的头部信息
|
||
const headers = new Headers();
|
||
const allowedHeaders = ['accept', 'content-type', 'authorization'];
|
||
for (const [key, value] of request.headers.entries()) {
|
||
if (allowedHeaders.includes(key.toLowerCase())) {
|
||
headers.set(key, value);
|
||
}
|
||
}
|
||
|
||
// 转发请求到目标API
|
||
const response = await fetch(targetUrl, {
|
||
method: request.method,
|
||
headers: headers,
|
||
body: request.body
|
||
});
|
||
|
||
// 设置安全相关的响应头
|
||
const responseHeaders = new Headers(response.headers);
|
||
responseHeaders.set('X-Content-Type-Options', 'nosniff');
|
||
responseHeaders.set('X-Frame-Options', 'DENY');
|
||
responseHeaders.set('Referrer-Policy', 'no-referrer');
|
||
|
||
// 返回API响应
|
||
return new Response(response.body, {
|
||
status: response.status,
|
||
headers: responseHeaders
|
||
});
|
||
|
||
} catch (error) {
|
||
// 处理请求错误
|
||
console.error('Failed to fetch:', error);
|
||
return new Response('Internal Server Error', { status: 500 });
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 从路径中提取API前缀和剩余部分
|
||
* @param {string} pathname - 请求路径
|
||
* @param {string[]} prefixes - 可用的API前缀列表
|
||
* @returns {[string|null, string|null]} - 返回匹配的前缀和剩余路径,如果没有匹配则返回[null, null]
|
||
*/
|
||
function extractPrefixAndRest(pathname, prefixes) {
|
||
for (const prefix of prefixes) {
|
||
if (pathname.startsWith(prefix)) {
|
||
return [prefix, pathname.slice(prefix.length)];
|
||
}
|
||
}
|
||
return [null, null];
|
||
} |