chore: sync local changes to Gitea
This commit is contained in:
40
README.md
40
README.md
@@ -10,7 +10,7 @@ English | [中文](./README.zh.md)
|
||||
|
||||
## Features
|
||||
|
||||
- 🔍 **Multi-engine Aggregation** - Use multiple search engines at the same time (Google, Brave, DuckDuckGo, Bing)
|
||||
- 🔍 **Multi-engine Aggregation** - Use DuckDuckGo and Bing at the same time
|
||||
- 🤖 **AI Enhanced (MCP)** - Native support for Model Context Protocol, one-click search tool integration for **OpenClaw** / **Claude Code** / **Codex**
|
||||
- ⚡ **Parallel Search** - All search engines are requested concurrently for faster results
|
||||
- 🛡️ **Fault Tolerance** - Failure of a single engine does not affect others; unresponsive engines are automatically marked
|
||||
@@ -132,7 +132,7 @@ Search using query parameters:
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare"
|
||||
|
||||
# Specify search engines
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=google,brave"
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=duckduckgo,bing"
|
||||
|
||||
# Use token authentication (if TOKEN env var is configured)
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&token=$YOUR-TOKEN"
|
||||
@@ -145,7 +145,7 @@ Submit search by POST form:
|
||||
```bash
|
||||
curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
-d "q=cloudflare" \
|
||||
-d "engines=google,brave"
|
||||
-d "engines=duckduckgo,bing"
|
||||
-d "token=$YOUR-TOKEN" # if TOKEN env var is configured
|
||||
```
|
||||
|
||||
@@ -160,13 +160,11 @@ Used to execute search queries and return aggregated results.
|
||||
| Parameter | Type | Required | Description | Example |
|
||||
| ------------- | -------- | -------- | ---------------------------------------------------------- | ---------------- |
|
||||
| `q` / `query` | `string` | yes | Search keyword | `cloudflare` |
|
||||
| `engines` | `string` | no | Specify search engines, separated by commas | `google,brave` |
|
||||
| `engines` | `string` | no | Specify search engines, separated by commas | `duckduckgo,bing` |
|
||||
| `token` | `string` | no/yes | Access token (required when `TOKEN` env var is configured) | `$YOUR-TOKEN` |
|
||||
|
||||
**Supported Search Engines**:
|
||||
|
||||
- `google` - Google Search (requires API Key configuration)
|
||||
- `brave` - Brave Search
|
||||
- `duckduckgo` - DuckDuckGo Search
|
||||
- `bing` - Bing Search
|
||||
|
||||
@@ -178,6 +176,8 @@ Used to execute search queries and return aggregated results.
|
||||
number_of_results: number; // Total number of results
|
||||
enabled_engines: string[]; // Enabled search engine list
|
||||
unresponsive_engines: string[]; // Unresponsive search engine list
|
||||
empty_engines: string[]; // Engines that responded with no results
|
||||
engine_errors: Record<string, string>; // Error message by engine
|
||||
results: Array<{
|
||||
title: string; // Result title
|
||||
description: string; // Result description
|
||||
@@ -191,12 +191,12 @@ Used to execute search queries and return aggregated results.
|
||||
|
||||
```bash
|
||||
# GET request
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=google,brave"
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=duckduckgo,bing"
|
||||
|
||||
# POST request
|
||||
curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "q=cloudflare&engines=google,brave"
|
||||
-d "q=cloudflare&engines=duckduckgo,bing"
|
||||
```
|
||||
|
||||
#### Response Example
|
||||
@@ -205,20 +205,22 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
{
|
||||
"query": "cloudflare",
|
||||
"number_of_results": 15,
|
||||
"enabled_engines": ["google", "brave", "duckduckgo"],
|
||||
"enabled_engines": ["duckduckgo", "bing"],
|
||||
"unresponsive_engines": [],
|
||||
"empty_engines": [],
|
||||
"engine_errors": {},
|
||||
"results": [
|
||||
{
|
||||
"title": "Cloudflare - The Web Performance & Security Company",
|
||||
"description": "Cloudflare is on a mission to help build a better Internet...",
|
||||
"url": "https://www.cloudflare.com/",
|
||||
"engine": "google"
|
||||
"engine": "duckduckgo"
|
||||
},
|
||||
{
|
||||
"title": "Cloudflare Workers",
|
||||
"description": "Deploy serverless code instantly across the globe...",
|
||||
"url": "https://workers.cloudflare.com/",
|
||||
"engine": "brave"
|
||||
"engine": "bing"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -230,9 +232,7 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
|
||||
| Engine | Description | Configuration Required | Enabled by Default |
|
||||
| -------------- | ---------------------------- | ------------------------------- | ------------------ |
|
||||
| **Google** | Google Custom Search API | Requires `GOOGLE_API_KEY` and `GOOGLE_CX` | yes |
|
||||
| **Brave** | Brave Search API | - | yes |
|
||||
| **DuckDuckGo** | DuckDuckGo Instant Answer API | - | yes |
|
||||
| **DuckDuckGo** | DuckDuckGo HTML search | - | yes |
|
||||
| **Bing** | Bing Search | - | no (unstable results) |
|
||||
|
||||
### Basic Working Approach
|
||||
@@ -249,13 +249,10 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
| Variable Name | Type | Default | Description |
|
||||
| ------------------ | -------- | -------- | --------------------------------------------------- |
|
||||
| `DEFAULT_TIMEOUT` | `string` | `"3000"` | Timeout per search engine request (milliseconds) |
|
||||
| `GOOGLE_API_KEY` | `string` | `null` | https://console.cloud.google.com/apis/credentials |
|
||||
| `GOOGLE_CX` | `string` | `null` | https://programmablesearchengine.google.com/ |
|
||||
| `TOKEN` | `string` | `null` | Access token. Enables auth when configured to prevent abuse |
|
||||
|
||||
**Notes**:
|
||||
|
||||
- Google Custom Search API free tier is limited to 100 requests per day
|
||||
- After `TOKEN` is configured, all requests must provide a valid token
|
||||
|
||||
### Configuration Methods
|
||||
@@ -266,8 +263,6 @@ Edit the `[vars]` section in `wrangler.toml`:
|
||||
|
||||
```toml
|
||||
[vars]
|
||||
GOOGLE_API_KEY = "your-google-api-key"
|
||||
GOOGLE_CX = "your-google-custom-search-cx"
|
||||
DEFAULT_TIMEOUT = "3000"
|
||||
TOKEN = "your-secret-token-here"
|
||||
```
|
||||
@@ -286,7 +281,7 @@ Build your own aggregated search API and combine results from multiple search en
|
||||
|
||||
```javascript
|
||||
const response = await fetch(
|
||||
"https://$YOUR-DOMAIN/search?q=javascript&engines=google,brave",
|
||||
"https://$YOUR-DOMAIN/search?q=javascript&engines=duckduckgo,bing",
|
||||
);
|
||||
const data = await response.json();
|
||||
console.log(`Found ${data.number_of_results} results`);
|
||||
@@ -311,7 +306,7 @@ async function search(query) {
|
||||
Collect results from multiple search engines for comparative analysis:
|
||||
|
||||
```javascript
|
||||
const engines = ["google", "brave", "duckduckgo"];
|
||||
const engines = ["duckduckgo", "bing"];
|
||||
const results = await fetch(
|
||||
`https://$YOUR-DOMAIN/search?q=AI&engines=${engines.join(",")}`,
|
||||
);
|
||||
@@ -339,7 +334,6 @@ With MCP (Model Context Protocol), AI assistants can directly call your search s
|
||||
- In Worker settings, click **Triggers** > **Add Custom Domain** to add a custom domain
|
||||
|
||||
2. **Search Engine Limits**
|
||||
- Google API free tier is limited to 100 requests per day
|
||||
- Other search engines generally do not have strict limits, but please use responsibly
|
||||
- Frequent requests may cause temporary rate limiting
|
||||
|
||||
@@ -380,7 +374,6 @@ A: Possible reasons:
|
||||
- Search engine API is temporarily unavailable or timed out
|
||||
- No relevant results for the search keyword
|
||||
- Search engine has rate-limited access
|
||||
- Google requires API Key configuration before use
|
||||
|
||||
You can check the `unresponsive_engines` field in the response to see which engines did not respond.
|
||||
|
||||
@@ -427,7 +420,6 @@ Issues and Pull Requests are welcome!
|
||||
|
||||
- [Project GitHub](https://github.com/Yrobot/cloudflare-search)
|
||||
- [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/)
|
||||
- [Google Custom Search API](https://developers.google.com/custom-search/v1/overview)
|
||||
|
||||
## Support the Project
|
||||
|
||||
|
||||
42
README.zh.md
42
README.zh.md
@@ -10,7 +10,7 @@
|
||||
|
||||
## 特性
|
||||
|
||||
- 🔍 **多引擎聚合** - 同时使用多个搜索引擎(Google、Brave、DuckDuckGo、Bing)
|
||||
- 🔍 **多引擎聚合** - 同时使用 DuckDuckGo 和 Bing 搜索引擎
|
||||
- 🤖 **AI 增强 (MCP)** - 原生支持 Model Context Protocol,一键为 **OpenClaw** / **Claude Code** / **Codex** 添加搜索工具
|
||||
- ⚡ **并行搜索** - 所有搜索引擎同时请求,快速返回结果
|
||||
- 🛡️ **容错机制** - 单个引擎失败不影响其他引擎,自动标记无响应引擎
|
||||
@@ -134,7 +134,7 @@ https://$YOUR-DOMAIN/
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare"
|
||||
|
||||
# 指定搜索引擎
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=google,brave"
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=duckduckgo,bing"
|
||||
|
||||
# 使用 token 鉴权(如果配置了 TOKEN 环境变量)
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&token=$YOUR-TOKEN"
|
||||
@@ -147,7 +147,7 @@ curl "https://$YOUR-DOMAIN/search?q=cloudflare&token=$YOUR-TOKEN"
|
||||
```bash
|
||||
curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
-d "q=cloudflare" \
|
||||
-d "engines=google,brave"
|
||||
-d "engines=duckduckgo,bing"
|
||||
-d "token=$YOUR-TOKEN" # 如果配置了 TOKEN 环境变量
|
||||
```
|
||||
|
||||
@@ -162,13 +162,11 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
| 参数 | 类型 | 必填 | 说明 | 示例 |
|
||||
| ------------- | -------- | ------ | ----------------------------------------- | -------------- |
|
||||
| `q` / `query` | `string` | yes | 搜索关键词 | `cloudflare` |
|
||||
| `engines` | `string` | no | 指定搜索引擎,多个用逗号分隔 | `google,brave` |
|
||||
| `token` | `string` | no/yse | 访问令牌(当配置了 TOKEN 环境变量时必填) | `$YOUR-TOKEN` |
|
||||
| `engines` | `string` | no | 指定搜索引擎,多个用逗号分隔 | `duckduckgo,bing` |
|
||||
| `token` | `string` | no/yes | 访问令牌(当配置了 TOKEN 环境变量时必填) | `$YOUR-TOKEN` |
|
||||
|
||||
**支持的搜索引擎**:
|
||||
|
||||
- `google` - Google 搜索(需要配置 API Key)
|
||||
- `brave` - Brave 搜索
|
||||
- `duckduckgo` - DuckDuckGo 搜索
|
||||
- `bing` - Bing 搜索
|
||||
|
||||
@@ -180,6 +178,8 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
number_of_results: number; // 结果总数
|
||||
enabled_engines: string[]; // 启用的搜索引擎列表
|
||||
unresponsive_engines: string[]; // 无响应的搜索引擎列表
|
||||
empty_engines: string[]; // 响应成功但无结果的搜索引擎列表
|
||||
engine_errors: Record<string, string>; // 各搜索引擎错误信息
|
||||
results: Array<{
|
||||
title: string; // 结果标题
|
||||
description: string; // 结果描述
|
||||
@@ -193,12 +193,12 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
|
||||
```bash
|
||||
# GET 请求
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=google,brave"
|
||||
curl "https://$YOUR-DOMAIN/search?q=cloudflare&engines=duckduckgo,bing"
|
||||
|
||||
# POST 请求
|
||||
curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "q=cloudflare&engines=google,brave"
|
||||
-d "q=cloudflare&engines=duckduckgo,bing"
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
@@ -207,20 +207,22 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
{
|
||||
"query": "cloudflare",
|
||||
"number_of_results": 15,
|
||||
"enabled_engines": ["google", "brave", "duckduckgo"],
|
||||
"enabled_engines": ["duckduckgo", "bing"],
|
||||
"unresponsive_engines": [],
|
||||
"empty_engines": [],
|
||||
"engine_errors": {},
|
||||
"results": [
|
||||
{
|
||||
"title": "Cloudflare - The Web Performance & Security Company",
|
||||
"description": "Cloudflare is on a mission to help build a better Internet...",
|
||||
"url": "https://www.cloudflare.com/",
|
||||
"engine": "google"
|
||||
"engine": "duckduckgo"
|
||||
},
|
||||
{
|
||||
"title": "Cloudflare Workers",
|
||||
"description": "Deploy serverless code instantly across the globe...",
|
||||
"url": "https://workers.cloudflare.com/",
|
||||
"engine": "brave"
|
||||
"engine": "bing"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -232,9 +234,7 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
|
||||
| 引擎 | 说明 | 是否需要配置 | 默认启用 |
|
||||
| -------------- | ------------------------ | ----------------------------- | --------------- |
|
||||
| **Google** | Google Custom Search API | 需要 GOOGLE_API_KEY GOOGLE_CX | yes |
|
||||
| **Brave** | Brave Search API | - | yes |
|
||||
| **DuckDuckGo** | DuckDuckGo 即时答案 API | - | yes |
|
||||
| **DuckDuckGo** | DuckDuckGo HTML 搜索 | - | yes |
|
||||
| **Bing** | Bing 搜索 | - | no (结果不稳定) |
|
||||
|
||||
### 基本工作方案
|
||||
@@ -251,13 +251,10 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
| 变量名 | 类型 | 默认值 | 说明 |
|
||||
| ----------------- | -------- | -------- | ------------------------------------------------- |
|
||||
| `DEFAULT_TIMEOUT` | `string` | `"3000"` | 单个搜索引擎的超时时间(毫秒) |
|
||||
| `GOOGLE_API_KEY` | `string` | `null` | https://console.cloud.google.com/apis/credentials |
|
||||
| `GOOGLE_CX` | `string` | `null` | https://programmablesearchengine.google.com/ |
|
||||
| `TOKEN` | `string` | `null` | 访问令牌,配置后启用鉴权,保护服务不被滥用 |
|
||||
|
||||
**注意**:
|
||||
|
||||
- Google Custom Search API 免费版每天限制 100 次请求
|
||||
- `TOKEN` 配置后,所有请求都需要提供有效的 token
|
||||
|
||||
### 配置方式
|
||||
@@ -268,8 +265,6 @@ curl -X POST "https://$YOUR-DOMAIN/search" \
|
||||
|
||||
```toml
|
||||
[vars]
|
||||
GOOGLE_API_KEY = "your-google-api-key"
|
||||
GOOGLE_CX = "your-google-custom-search-cx"
|
||||
DEFAULT_TIMEOUT = "3000"
|
||||
TOKEN = "your-secret-token-here"
|
||||
```
|
||||
@@ -288,7 +283,7 @@ TOKEN = "your-secret-token-here"
|
||||
|
||||
```javascript
|
||||
const response = await fetch(
|
||||
"https://$YOUR-DOMAIN/search?q=javascript&engines=google,brave",
|
||||
"https://$YOUR-DOMAIN/search?q=javascript&engines=duckduckgo,bing",
|
||||
);
|
||||
const data = await response.json();
|
||||
console.log(`找到 ${data.number_of_results} 个结果`);
|
||||
@@ -313,7 +308,7 @@ async function search(query) {
|
||||
收集多个搜索引擎的结果进行对比分析:
|
||||
|
||||
```javascript
|
||||
const engines = ["google", "brave", "duckduckgo"];
|
||||
const engines = ["duckduckgo", "bing"];
|
||||
const results = await fetch(
|
||||
`https://$YOUR-DOMAIN/search?q=AI&engines=${engines.join(",")}`,
|
||||
);
|
||||
@@ -341,7 +336,6 @@ const byEngine = data.results.reduce((acc, result) => {
|
||||
- 在 Worker 设置中点击 **Triggers** > **Add Custom Domain** 添加自定义域名
|
||||
|
||||
2. **搜索引擎限制**
|
||||
- Google API 免费版每天限制 100 次请求
|
||||
- 其他搜索引擎一般没有严格限制,但请合理使用
|
||||
- 频繁请求可能导致被临时限制访问
|
||||
|
||||
@@ -382,7 +376,6 @@ A: 可能原因:
|
||||
- 搜索引擎 API 临时不可用或响应超时
|
||||
- 搜索关键词没有相关结果
|
||||
- 搜索引擎限制了访问频率
|
||||
- Google 需要配置 API Key 才能使用
|
||||
|
||||
可以查看返回的 `unresponsive_engines` 字段了解哪些引擎没有响应。
|
||||
|
||||
@@ -429,7 +422,6 @@ A: 建议配置 `TOKEN` 环境变量启用鉴权:
|
||||
|
||||
- [项目 GitHub](https://github.com/Yrobot/cloudflare-search)
|
||||
- [Cloudflare Workers 文档](https://developers.cloudflare.com/workers/)
|
||||
- [Google Custom Search API](https://developers.google.com/custom-search/v1/overview)
|
||||
|
||||
## 支持一下
|
||||
|
||||
|
||||
8
envs.js
8
envs.js
@@ -3,20 +3,14 @@ export const env = {
|
||||
DEFAULT_TIMEOUT: "3000",
|
||||
|
||||
// 支持的搜索引擎列表 - Supported search engines
|
||||
SUPPORTED_ENGINES: ["google", "brave", "duckduckgo", "bing"],
|
||||
SUPPORTED_ENGINES: ["duckduckgo", "bing"],
|
||||
|
||||
// 默认启用的搜索引擎 - Default enabled engines
|
||||
DEFAULT_ENGINES: [
|
||||
"google",
|
||||
"brave",
|
||||
"duckduckgo",
|
||||
// "bing" // Bing 目前结果不稳定,默认禁用 - Bing results are currently unstable, disabled by default
|
||||
],
|
||||
|
||||
// Google Custom Search API credentials
|
||||
GOOGLE_API_KEY: null,
|
||||
GOOGLE_CX: null,
|
||||
|
||||
// API 访问令牌 - API access token for authentication
|
||||
// 如果设置了 TOKEN,则所有 /search 请求都需要在 header 或 query 中提供此 token
|
||||
// If TOKEN is set, all /search requests must provide this token in header or query
|
||||
|
||||
4
index.d.ts
vendored
4
index.d.ts
vendored
@@ -22,6 +22,8 @@ export type searchAll = (params: {
|
||||
number_of_results: number;
|
||||
enabled_engines: string[];
|
||||
unresponsive_engines: string[];
|
||||
empty_engines: string[];
|
||||
engine_errors: Record<string, string>;
|
||||
results: Array<ResultItem & { engine: string }>;
|
||||
}>;
|
||||
|
||||
@@ -29,7 +31,5 @@ export interface Env {
|
||||
DEFAULT_TIMEOUT?: string;
|
||||
SUPPORTED_ENGINES?: string[];
|
||||
DEFAULT_ENGINES?: string[];
|
||||
GOOGLE_API_KEY?: string;
|
||||
GOOGLE_CX?: string;
|
||||
TOKEN?: string;
|
||||
}
|
||||
|
||||
@@ -86,11 +86,11 @@ const SEARCH_INPUT_SCHEMA = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
enum: ["google", "brave", "duckduckgo", "bing"],
|
||||
enum: ["duckduckgo", "bing"],
|
||||
},
|
||||
description:
|
||||
"Optional: Array of search engines to use. If not specified, uses default engines. " +
|
||||
"Available engines: google, brave, duckduckgo, bing",
|
||||
"Available engines: duckduckgo, bing",
|
||||
},
|
||||
},
|
||||
required: ["query"],
|
||||
@@ -106,7 +106,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
name: "web_search",
|
||||
description:
|
||||
"Search the web for current information, news, or any topic. " +
|
||||
"Uses multiple engines (Brave, DuckDuckGo, Google, Bing) simultaneously " +
|
||||
"Uses DuckDuckGo and Bing simultaneously " +
|
||||
"and returns aggregated results with source URLs. " +
|
||||
"Use this when you need real-time information not in your training data. ",
|
||||
inputSchema: SEARCH_INPUT_SCHEMA,
|
||||
@@ -114,7 +114,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
{
|
||||
name: "search",
|
||||
description:
|
||||
"Search across multiple search engines (Google, Brave, DuckDuckGo, Bing) and return aggregated results. " +
|
||||
"Search across DuckDuckGo and Bing and return aggregated results. " +
|
||||
"This tool provides comprehensive search results from multiple sources, with source attribution for each result.",
|
||||
inputSchema: SEARCH_INPUT_SCHEMA,
|
||||
},
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
"free-search",
|
||||
"privacy",
|
||||
"aggregated-search",
|
||||
"google",
|
||||
"brave",
|
||||
"duckduckgo",
|
||||
"bing"
|
||||
],
|
||||
|
||||
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB |
@@ -1,7 +1,5 @@
|
||||
// HTTPS_PROXY=http://localhost:7777 bun ./output/cloudflare-search/utils/dev.js
|
||||
|
||||
import searchBrave from "./searchBrave.js";
|
||||
import searchGoogle from "./searchGoogle.js";
|
||||
import searchDuckDuckGo from "./searchDuckDuckGo.js";
|
||||
import searchBing from "./searchBing.js";
|
||||
|
||||
|
||||
118
utils/getHTML.js
118
utils/getHTML.js
@@ -5,7 +5,6 @@ import { env } from "../envs.js";
|
||||
// ============================================
|
||||
|
||||
export function getSearchHtml() {
|
||||
const GOOGLE_ENABLED = env.GOOGLE_API_KEY && env.GOOGLE_CX;
|
||||
const TOKEN_ENABLED = !!env.TOKEN;
|
||||
const DEFAULT_ENGINES = env.DEFAULT_ENGINES || [];
|
||||
const handlerEngineDefaultChecked = (engine) =>
|
||||
@@ -94,7 +93,7 @@ export function getSearchHtml() {
|
||||
</h1>
|
||||
<div class="mt-6 text-base text-zinc-600 dark:text-zinc-400">
|
||||
<p class="">
|
||||
基于 Cloudflare Workers 的多引擎聚合搜索服务。并行搜索 Google、DuckDuckGo、Bing、Brave 四大引擎,快速获取更全面的搜索结果。
|
||||
基于 Cloudflare Workers 的多引擎聚合搜索服务。并行搜索 DuckDuckGo、Bing 等搜索引擎,快速获取更全面的搜索结果。
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
如果这个项目对你有帮助,可以
|
||||
@@ -112,30 +111,14 @@ export function getSearchHtml() {
|
||||
|
||||
<!-- 服务状态 -->
|
||||
<div class="mt-8 rounded-2xl border ${
|
||||
GOOGLE_ENABLED && !TOKEN_ENABLED
|
||||
? "border-green-200 bg-green-50 dark:border-green-800/40 dark:bg-green-900/10"
|
||||
: !GOOGLE_ENABLED || TOKEN_ENABLED
|
||||
TOKEN_ENABLED
|
||||
? "border-amber-200 bg-amber-50 dark:border-amber-800/40 dark:bg-amber-900/10"
|
||||
: "border-zinc-100 dark:border-zinc-700/40"
|
||||
: "border-green-200 bg-green-50 dark:border-green-800/40 dark:bg-green-900/10"
|
||||
} p-6">
|
||||
<h2 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-3">
|
||||
⚙️ 服务配置状态
|
||||
</h2>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-zinc-700 dark:text-zinc-300">Google 搜索引擎</span>
|
||||
<span class="${
|
||||
GOOGLE_ENABLED
|
||||
? "text-green-600 dark:text-green-400"
|
||||
: "text-amber-600 dark:text-amber-400"
|
||||
}">
|
||||
${
|
||||
GOOGLE_ENABLED
|
||||
? "✓ 已配置"
|
||||
: "○ 未配置 (需要 API Key)"
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-zinc-700 dark:text-zinc-300">访问鉴权</span>
|
||||
<span class="${
|
||||
@@ -147,40 +130,17 @@ export function getSearchHtml() {
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-zinc-700 dark:text-zinc-300">其他引擎 (Brave/DuckDuckGo/Bing)</span>
|
||||
<span class="text-zinc-700 dark:text-zinc-300">搜索引擎 (DuckDuckGo/Bing)</span>
|
||||
<span class="text-green-600 dark:text-green-400">✓ 可用</span>
|
||||
</div>
|
||||
</div>
|
||||
${
|
||||
!GOOGLE_ENABLED
|
||||
? `
|
||||
<div class="mt-4 pt-4 border-t border-amber-200 dark:border-amber-800/40">
|
||||
<p class="text-xs text-amber-700 dark:text-amber-400">
|
||||
💡 提示: 配置 Google API 后可使用 Google 搜索引擎。在 Cloudflare Dashboard 的 Worker 设置中添加环境变量:<br/>
|
||||
• <code class="px-1 py-0.5 bg-amber-100 dark:bg-amber-900/30 rounded">GOOGLE_API_KEY</code> - <a href="https://console.cloud.google.com/apis/credentials" target="_blank" class="underline hover:text-amber-900 dark:hover:text-amber-100">获取 API Key</a><br/>
|
||||
• <code class="px-1 py-0.5 bg-amber-100 dark:bg-amber-900/30 rounded">GOOGLE_CX</code> - <a href="https://programmablesearchengine.google.com/" target="_blank" class="underline hover:text-amber-900 dark:hover:text-amber-100">获取 CX ID</a>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
!TOKEN_ENABLED
|
||||
? `
|
||||
<div class="mt-4 pt-4 border-t ${
|
||||
!GOOGLE_ENABLED
|
||||
? "border-amber-200 dark:border-amber-800/40"
|
||||
: "border-green-200 dark:border-green-800/40"
|
||||
}">
|
||||
<p class="text-xs ${
|
||||
!GOOGLE_ENABLED
|
||||
? "text-amber-700 dark:text-amber-400"
|
||||
: "text-green-700 dark:text-green-400"
|
||||
}">
|
||||
<div class="mt-4 pt-4 border-t border-green-200 dark:border-green-800/40">
|
||||
<p class="text-xs text-green-700 dark:text-green-400">
|
||||
💡 建议:为防止服务被滥用,建议在 Cloudflare Dashboard 的 Worker 设置中添加环境变量 <code class="px-1 py-0.5 ${
|
||||
!GOOGLE_ENABLED
|
||||
? "bg-amber-100 dark:bg-amber-900/30"
|
||||
: "bg-green-100 dark:bg-green-900/30"
|
||||
"bg-green-100 dark:bg-green-900/30"
|
||||
} rounded">TOKEN</code> 启用访问鉴权。
|
||||
</p>
|
||||
</div>
|
||||
@@ -213,29 +173,6 @@ export function getSearchHtml() {
|
||||
选择搜索引擎 (可多选)
|
||||
</label>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<label class="flex items-center space-x-2 ${
|
||||
GOOGLE_ENABLED
|
||||
? "cursor-pointer"
|
||||
: "cursor-not-allowed opacity-50"
|
||||
}" ${
|
||||
!GOOGLE_ENABLED ? 'title="Google 引擎需要配置 API Key"' : ""
|
||||
}>
|
||||
<input type="checkbox" name="engine" value="google" ${
|
||||
GOOGLE_ENABLED
|
||||
? handlerEngineDefaultChecked("google")
|
||||
: "disabled"
|
||||
} class="rounded text-blue-500 focus:ring-blue-500 ${
|
||||
!GOOGLE_ENABLED ? "cursor-not-allowed" : ""
|
||||
}">
|
||||
<span class="text-sm text-zinc-700 dark:text-zinc-300">
|
||||
Google
|
||||
${
|
||||
!GOOGLE_ENABLED
|
||||
? '<span class="text-xs text-zinc-400 dark:text-zinc-500 ml-1">(未配置)</span>'
|
||||
: ""
|
||||
}
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 cursor-pointer">
|
||||
<input type="checkbox" name="engine" value="duckduckgo" ${handlerEngineDefaultChecked(
|
||||
"duckduckgo"
|
||||
@@ -251,12 +188,6 @@ export function getSearchHtml() {
|
||||
<span class="text-xs text-zinc-400 dark:text-zinc-500 ml-1">(不稳定)</span>
|
||||
</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-2 cursor-pointer">
|
||||
<input type="checkbox" name="engine" value="brave" ${handlerEngineDefaultChecked(
|
||||
"brave"
|
||||
)} class="rounded text-blue-500 focus:ring-blue-500">
|
||||
<span class="text-sm text-zinc-700 dark:text-zinc-300">Brave</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -343,14 +274,16 @@ export function getSearchHtml() {
|
||||
<pre class="text-xs overflow-x-auto"><code>{
|
||||
"query": "cloudflare", // 搜索关键词
|
||||
"number_of_results": 15, // 结果总数
|
||||
"enabled_engines": ["google", ...], // 启用的搜索引擎列表
|
||||
"enabled_engines": ["duckduckgo", ...], // 启用的搜索引擎列表
|
||||
"unresponsive_engines": [], // 无响应的搜索引擎列表
|
||||
"empty_engines": [], // 响应成功但无结果的搜索引擎列表
|
||||
"engine_errors": {}, // 各搜索引擎错误信息
|
||||
"results": [
|
||||
{
|
||||
"title": "...", // 结果标题
|
||||
"description": "...", // 结果描述
|
||||
"url": "...", // 结果链接
|
||||
"engine": "google" // 来源引擎
|
||||
"engine": "duckduckgo" // 来源引擎
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
@@ -365,21 +298,6 @@ export function getSearchHtml() {
|
||||
🚀 支持的搜索引擎
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="rounded-lg bg-zinc-50 p-4 dark:bg-zinc-800/50 ${
|
||||
!GOOGLE_ENABLED ? "opacity-50" : ""
|
||||
}">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="font-medium text-zinc-900 dark:text-zinc-100">Google</div>
|
||||
${
|
||||
GOOGLE_ENABLED
|
||||
? '<span class="text-xs text-green-600 dark:text-green-400">✓ 可用</span>'
|
||||
: '<span class="text-xs text-amber-600 dark:text-amber-400">○ 需配置</span>'
|
||||
}
|
||||
</div>
|
||||
<p class="text-xs text-zinc-600 dark:text-zinc-400">
|
||||
全球最大的搜索引擎,需要配置 Google Custom Search API
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg bg-zinc-50 p-4 dark:bg-zinc-800/50">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="font-medium text-zinc-900 dark:text-zinc-100">DuckDuckGo</div>
|
||||
@@ -387,13 +305,6 @@ export function getSearchHtml() {
|
||||
</div>
|
||||
<p class="text-xs text-zinc-600 dark:text-zinc-400">注重隐私保护的搜索引擎,无需配置</p>
|
||||
</div>
|
||||
<div class="rounded-lg bg-zinc-50 p-4 dark:bg-zinc-800/50">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="font-medium text-zinc-900 dark:text-zinc-100">Brave Search</div>
|
||||
<span class="text-xs text-green-600 dark:text-green-400">✓ 可用</span>
|
||||
</div>
|
||||
<p class="text-xs text-zinc-600 dark:text-zinc-400">独立的搜索引擎,无需配置</p>
|
||||
</div>
|
||||
<div class="rounded-lg bg-zinc-50 p-4 dark:bg-zinc-800/50 opacity-60">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="font-medium text-zinc-900 dark:text-zinc-100">Bing</div>
|
||||
@@ -425,11 +336,6 @@ export function getSearchHtml() {
|
||||
在 Cloudflare Dashboard → Workers & Pages → 您的 Worker → 设置 → 变量 中添加:
|
||||
</p>
|
||||
<ul class="text-xs text-blue-700 dark:text-blue-300 mt-1 ml-4 list-disc">
|
||||
${
|
||||
!GOOGLE_ENABLED
|
||||
? '<li><code class="px-1 py-0.5 bg-blue-100 dark:bg-blue-900/30 rounded">GOOGLE_API_KEY</code> 和 <code class="px-1 py-0.5 bg-blue-100 dark:bg-blue-900/30 rounded">GOOGLE_CX</code> - 启用 Google 搜索 (<a href="https://console.cloud.google.com/apis/credentials" target="_blank" class="underline hover:text-blue-900 dark:hover:text-blue-100">获取 API Key</a> / <a href="https://programmablesearchengine.google.com/" target="_blank" class="underline hover:text-blue-900 dark:hover:text-blue-100">获取 CX</a>)</li>'
|
||||
: ""
|
||||
}
|
||||
${
|
||||
!TOKEN_ENABLED
|
||||
? '<li><code class="px-1 py-0.5 bg-blue-100 dark:bg-blue-900/30 rounded">TOKEN</code> - 启用访问鉴权 (建议)</li>'
|
||||
@@ -613,7 +519,7 @@ export function getSearchHtml() {
|
||||
const tokenBodyParam = TOKEN_ENABLED && currentToken ? \`&token=\${currentToken}\` : '';
|
||||
|
||||
document.getElementById('apiExample1').textContent = currentOrigin + '/search?q=cloudflare' + tokenParam;
|
||||
document.getElementById('apiExample2').textContent = 'curl -X POST "' + currentOrigin + '/search" -d "q=cloudflare&engines=google,brave' + tokenBodyParam + '"';
|
||||
document.getElementById('apiExample2').textContent = 'curl -X POST "' + currentOrigin + '/search" -d "q=cloudflare&engines=duckduckgo,bing' + tokenBodyParam + '"';
|
||||
document.getElementById('mcp-config-json').innerHTML = \`{
|
||||
"mcpServers": {
|
||||
"cloudflare-search": {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { normalizeResults } from "./index.js";
|
||||
|
||||
// type subSearch under index.d.ts
|
||||
// TODO: support language, time_range, pageno
|
||||
async function searchBrave({ query, language, time_range, pageno, signal }) {
|
||||
const searchUrl = `https://search.brave.com/search?q=${encodeURIComponent(
|
||||
query
|
||||
)}&spellcheck=0&source=web&summary=0`;
|
||||
|
||||
const response = await fetch(searchUrl, {
|
||||
signal,
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7",
|
||||
priority: "u=0, i",
|
||||
"sec-ch-ua":
|
||||
'"Chromium";v="142", "Google Chrome";v="142", "Not_A Brand";v="99"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"macOS"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
cookie:
|
||||
"ui_lang=zh; country=all; safesearch=off; useLocation=0; __Secure-sku#brave-search-captcha=eyJ0eXBlIjoic2luZ2xlLXVzZSIsInZlcnNpb24iOjEsInNrdSI6ImJyYXZlLXNlYXJjaC1jYXB0Y2hhIiwicHJlc2VudGF0aW9uIjoiZXlKcGMzTjFaWElpT2lKaWNtRjJaUzVqYjIwL2MydDFQV0p5WVhabExYTmxZWEpqYUMxallYQjBZMmhoSWl3aWMybG5ibUYwZFhKbElqb2lPRFY2YVU1S1JVMXFTbXhvTTI5TE5UUXhTMFJtTlZkdU4yWjJiall2VmtVMVVHTmFkMlIzV2poMGFreDBTR0V2Tm1SVVMyVjRZWFpSZVVKSFNIcHRVR0ZLUWtSbVFUTkxlV3gzUjNaSVkyZ3ZUVXhvTTFFOVBTSXNJblFpT2lKM1dVZzJTVTFVTlRsTGMzRnpaM1ptTWpVMVRDOHpOVlZrYzFVNU1sRnlSSGxGZVdoWVlXSXdOa2x3TVhscU1HMUlUa0ozUjNGVVpYTlliWGh1TlVGREx5OXdLMUpJUjJzemJrTTJVWHBQWW1aUFpVOHlVVDA5SW4wPSJ9",
|
||||
},
|
||||
referrer: "https://search.brave.com/search?source=web",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`Brave search failed: ${response.status}`);
|
||||
return [];
|
||||
}
|
||||
const html = await response.text();
|
||||
|
||||
if (!html) throw new Error("html is empty");
|
||||
|
||||
let data;
|
||||
|
||||
html.split("\n").forEach((line) => {
|
||||
if (data) return;
|
||||
if (line.trimStart().startsWith(`data: [{type:"data",`)) {
|
||||
const pureLine = line.trim();
|
||||
const jsonStr = pureLine.slice(
|
||||
"data: ".length,
|
||||
pureLine.endsWith(",") ? -1 : undefined
|
||||
);
|
||||
data = eval("(" + jsonStr + ")");
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) throw new Error("can't find data in html");
|
||||
|
||||
let result;
|
||||
|
||||
data.forEach((item) => {
|
||||
if (result) return;
|
||||
if (item?.data?.body?.response?.web?.results)
|
||||
result = normalizeResults(item.data.body.response.web.results);
|
||||
});
|
||||
|
||||
if (!result) throw new Error("can't find result in data");
|
||||
if (!(result instanceof Array)) throw new Error("result is not an array");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export default searchBrave;
|
||||
@@ -1,34 +0,0 @@
|
||||
import { normalizeResults } from "./index.js";
|
||||
import { env } from "../envs.js";
|
||||
|
||||
// type subSearch under index.d.ts
|
||||
// TODO: support language, time_range, pageno
|
||||
async function searchGoogle({ query, language, time_range, pageno, signal }) {
|
||||
const searchUrl = `https://www.googleapis.com/customsearch/v1?key=${env.GOOGLE_API_KEY}&cx=${env.GOOGLE_CX}&q=${encodeURIComponent(
|
||||
query
|
||||
)}`;
|
||||
|
||||
const response = await fetch(searchUrl, { signal });
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(await response.text());
|
||||
return [];
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const results = [];
|
||||
|
||||
if (data.items && Array.isArray(data.items)) {
|
||||
for (const item of data.items) {
|
||||
results.push({
|
||||
title: item.title,
|
||||
url: item.link,
|
||||
content: item.snippet || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return normalizeResults(results);
|
||||
}
|
||||
|
||||
export default searchGoogle;
|
||||
50
worker.js
50
worker.js
@@ -1,13 +1,9 @@
|
||||
import { env, setEnv } from "./envs.js";
|
||||
import { getSearchHtml } from "./utils/getHTML.js";
|
||||
import searchGoogle from "./utils/searchGoogle.js";
|
||||
import searchBrave from "./utils/searchBrave.js";
|
||||
import searchDuckDuckGo from "./utils/searchDuckDuckGo.js";
|
||||
import searchBing from "./utils/searchBing.js";
|
||||
|
||||
const SEARCH_ENGINES = {
|
||||
google: searchGoogle,
|
||||
brave: searchBrave,
|
||||
duckduckgo: searchDuckDuckGo,
|
||||
bing: searchBing,
|
||||
};
|
||||
@@ -23,12 +19,7 @@ function parseEngines(enginesParam) {
|
||||
return enginesParam
|
||||
.split(",")
|
||||
.map((e) => e.trim().toLowerCase())
|
||||
.filter((e) => {
|
||||
// Filter out google if not enabled
|
||||
if (e === "google" && !(env.GOOGLE_API_KEY && env.GOOGLE_CX))
|
||||
return false;
|
||||
return env.SUPPORTED_ENGINES.includes(e);
|
||||
});
|
||||
.filter((e) => env.SUPPORTED_ENGINES.includes(e));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,28 +32,35 @@ async function searchSingle(engineName, query) {
|
||||
const searchFn = SEARCH_ENGINES[engineName];
|
||||
if (!searchFn) {
|
||||
console.warn(`Unknown engine: ${engineName}`);
|
||||
return [];
|
||||
return { results: [], error: "Unknown engine" };
|
||||
}
|
||||
|
||||
// 创建 AbortController 用于取消请求
|
||||
const controller = new AbortController();
|
||||
const timeout = parseInt(env.DEFAULT_TIMEOUT ?? "3000", 10);
|
||||
let timeoutId;
|
||||
|
||||
try {
|
||||
// 设置超时自动取消
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
|
||||
const result = await searchFn({ query, signal: controller.signal });
|
||||
const results = await searchFn({ query, signal: controller.signal });
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
return result;
|
||||
return { results, error: null };
|
||||
} catch (error) {
|
||||
const message =
|
||||
error.name === "AbortError"
|
||||
? `Timeout after ${timeout}ms`
|
||||
: error.message || String(error);
|
||||
|
||||
if (error.name === "AbortError") {
|
||||
console.error(`[${engineName}] Timeout after ${timeout}ms`);
|
||||
console.error(`[${engineName}] ${message}`);
|
||||
} else {
|
||||
console.error(`[${engineName}] Error:`, error.message);
|
||||
console.error(`[${engineName}] Error:`, message);
|
||||
}
|
||||
return [];
|
||||
clearTimeout(timeoutId);
|
||||
return { results: [], error: message };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,21 +84,27 @@ async function searchAll({ query, engines }) {
|
||||
// Collect resultsArr and track unresponsive engines
|
||||
const results = [];
|
||||
const unresponsive = [];
|
||||
const empty = [];
|
||||
const errors = {};
|
||||
|
||||
resultsArr.forEach((result, index) => {
|
||||
const engineName = enabledEngines[index];
|
||||
if (result.status === "fulfilled" && result.value.length > 0) {
|
||||
if (result.status === "fulfilled" && result.value.results.length > 0) {
|
||||
results.push(
|
||||
...result.value.map((item) => ({
|
||||
...result.value.results.map((item) => ({
|
||||
...item,
|
||||
engine: engineName,
|
||||
}))
|
||||
);
|
||||
} else if (result.status === "fulfilled" && result.value.error) {
|
||||
unresponsive.push(engineName);
|
||||
errors[engineName] = result.value.error;
|
||||
} else if (result.status === "fulfilled") {
|
||||
empty.push(engineName);
|
||||
} else {
|
||||
unresponsive.push(engineName);
|
||||
if (result.status === "rejected") {
|
||||
console.error(`[${engineName}] Rejected:`, result.reason);
|
||||
}
|
||||
errors[engineName] = result.reason?.message || String(result.reason);
|
||||
console.error(`[${engineName}] Rejected:`, result.reason);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -109,6 +113,8 @@ async function searchAll({ query, engines }) {
|
||||
number_of_results: results.length,
|
||||
enabled_engines: enabledEngines,
|
||||
unresponsive_engines: unresponsive,
|
||||
empty_engines: empty,
|
||||
engine_errors: errors,
|
||||
results,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Cloudflare Worker 配置文件
|
||||
# 更多配置选项: https://developers.cloudflare.com/workers/wrangler/configuration/
|
||||
|
||||
# Worker 名称(修改为你想要的名称)
|
||||
name = "cloudflare-search"
|
||||
|
||||
@@ -15,45 +12,16 @@ compatibility_date = "2024-12-04"
|
||||
# 设置为 true 会自动分配一个 xxx.workers.dev 域名
|
||||
workers_dev = true
|
||||
|
||||
# 账号 ID (可选,部署时会自动填充)
|
||||
# account_id = "your-account-id"
|
||||
|
||||
# ============================================
|
||||
# 路由配置(可选)
|
||||
# ============================================
|
||||
# 如果你想将 Worker 绑定到自定义域名,取消注释并配置:
|
||||
# routes = [
|
||||
# { pattern = "search.yourdomain.com/*", zone_name = "yourdomain.com" }
|
||||
# ]
|
||||
|
||||
# ============================================
|
||||
# 环境变量(可选)
|
||||
# ============================================
|
||||
[vars]
|
||||
# Google Custom Search API 配置
|
||||
# GOOGLE_API_KEY = ""
|
||||
# GOOGLE_CX = ""
|
||||
|
||||
# API 访问令牌(可选)
|
||||
# 配置后,所有 /search 请求都需要提供此 token 进行鉴权
|
||||
# 可以通过 Authorization header (Bearer token) 或 query 参数 (?token=xxx) 传递
|
||||
# TOKEN = ""
|
||||
TOKEN = "shumengya520"
|
||||
|
||||
# ============================================
|
||||
# 环境配置(可选)
|
||||
# ============================================
|
||||
# 生产环境配置
|
||||
# [env.production]
|
||||
# name = "cloudflare-search-prod"
|
||||
# workers_dev = false
|
||||
# routes = [
|
||||
# { pattern = "search.yourdomain.com/*", zone_name = "yourdomain.com" }
|
||||
# ]
|
||||
|
||||
# 开发环境配置
|
||||
# [env.staging]
|
||||
# name = "cloudflare-search-staging"
|
||||
# workers_dev = true
|
||||
|
||||
# ============================================
|
||||
# 资源限制(可选)
|
||||
|
||||
Reference in New Issue
Block a user