fix(websearch): improve error handling and response validation

This commit is contained in:
eeee0717 2025-04-06 17:08:37 +08:00 committed by kangfenmao
parent 581ad5fbda
commit 3491eec86b
2 changed files with 36 additions and 28 deletions

View File

@ -16,19 +16,35 @@ export default class SearxngProvider extends BaseWebSearchProvider {
throw new Error('API host is required for SearxNG provider') throw new Error('API host is required for SearxNG provider')
} }
this.apiHost = provider.apiHost this.apiHost = provider.apiHost
this.searxng = new SearxngClient({ apiBaseUrl: this.apiHost }) try {
this.searxng = new SearxngClient({ apiBaseUrl: this.apiHost })
} catch (error) {
throw new Error(
`Failed to initialize SearxNG client: ${error instanceof Error ? error.message : 'Unknown error'}`
)
}
this.initEngines().catch((err) => console.error('Failed to initialize SearxNG engines:', err)) this.initEngines().catch((err) => console.error('Failed to initialize SearxNG engines:', err))
} }
private async initEngines(): Promise<void> { private async initEngines(): Promise<void> {
try { try {
const response = await axios.get(`${this.apiHost}/config`, { timeout: 5000 }) console.log(`Initializing SearxNG with API host: ${this.apiHost}`)
const response = await axios.get(`${this.apiHost}/config`, {
timeout: 5000,
validateStatus: (status) => status === 200 // 仅接受 200 状态码
})
if (!response.data || !Array.isArray(response.data.engines)) { if (!response.data) {
throw new Error('Invalid response format from SearxNG config endpoint') throw new Error('Empty response from SearxNG config endpoint')
} }
this.engines = response.data.engines if (!Array.isArray(response.data.engines)) {
throw new Error('Invalid response format: "engines" property not found or not an array')
}
const allEngines = response.data.engines
console.log(`Found ${allEngines.length} total engines in SearxNG`)
this.engines = allEngines
.filter( .filter(
(engine: { enabled: boolean; categories: string[]; name: string }) => (engine: { enabled: boolean; categories: string[]; name: string }) =>
engine.enabled && engine.enabled &&
@ -38,11 +54,17 @@ export default class SearxngProvider extends BaseWebSearchProvider {
) )
.map((engine) => engine.name) .map((engine) => engine.name)
if (this.engines.length === 0) {
throw new Error('No enabled general web search engines found in SearxNG configuration')
}
this.isInitialized = true this.isInitialized = true
console.log(`SearxNG initialized with ${this.engines.length} engines`) console.log(`SearxNG initialized successfully with ${this.engines.length} engines: ${this.engines.join(', ')}`)
} catch (err) { } catch (err) {
this.isInitialized = false
console.error('Failed to fetch SearxNG engine configuration:', err) console.error('Failed to fetch SearxNG engine configuration:', err)
this.engines = [] throw new Error(`Failed to initialize SearxNG: ${err}`)
} }
} }
@ -57,14 +79,6 @@ export default class SearxngProvider extends BaseWebSearchProvider {
await this.initEngines().catch(() => {}) // Ignore errors await this.initEngines().catch(() => {}) // Ignore errors
} }
// 如果engines为空直接返回空结果
if (this.engines.length === 0) {
return {
query: query,
results: []
}
}
const result = await this.searxng.search({ const result = await this.searxng.search({
query: query, query: query,
engines: this.engines as any, engines: this.engines as any,
@ -85,13 +99,9 @@ export default class SearxngProvider extends BaseWebSearchProvider {
} }
}) })
} }
} catch (err) { } catch (error) {
console.error('Search failed:', err) console.error('Searxng search failed:', error)
// Return empty results instead of throwing to prevent UI crashes throw new Error(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
return {
query: query,
results: []
}
} }
} }
} }

View File

@ -95,9 +95,7 @@ class WebSearchService {
return await webSearchEngine.search(formattedQuery, maxResults, excludeDomains) return await webSearchEngine.search(formattedQuery, maxResults, excludeDomains)
} catch (error) { } catch (error) {
console.error('Search failed:', error) console.error('Search failed:', error)
return { throw new Error(`Search failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
results: []
}
} }
} }
@ -110,9 +108,9 @@ class WebSearchService {
public async checkSearch(provider: WebSearchProvider): Promise<{ valid: boolean; error?: any }> { public async checkSearch(provider: WebSearchProvider): Promise<{ valid: boolean; error?: any }> {
try { try {
const response = await this.search(provider, 'test query') const response = await this.search(provider, 'test query')
console.log('Search response:', response)
// 优化的判断条件:检查结果是否有效且没有错误 // 优化的判断条件:检查结果是否有效且没有错误
return { valid: response.results.length > 0, error: undefined } return { valid: response.results !== undefined, error: undefined }
} catch (error) { } catch (error) {
return { valid: false, error } return { valid: false, error }
} }