搜索web后端调用python搜索接口.md
6.43 KB
非常好的问题!让我详细解释一下搜索应用的调用链路和 OAuth 的关系。
调用链路说明
1. OAuth 认证的作用
OAuth 不是用于前端搜索调用的,它主要用于:
graph LR
A[商家安装APP] --> B[OAuth授权]
B --> C[获取Access Token]
C --> D[后端拉取商品数据]
D --> E[建立ES索引]
E --> F[搜索服务就绪]
OAuth Token 的用途:
- ✅ 你的后端调用店匠 Admin API(拉取商品、订单、客户数据)
- ✅ 注册 Webhook(接收数据变更通知)
- ❌ 不用于前端买家搜索时的调用
2. 前端搜索的实际调用链路
当买家在店铺搜索商品时:
买家浏览器 → 搜索框组件(Liquid/JS) → 你的搜索API → Elasticsearch → 返回结果
关键点:
- 前端 JavaScript 直接调用你的公开搜索 API
- 不需要 OAuth Token
- 需要传递
store_id参数来标识是哪个店铺
3. 搜索接口的两种方案
[2 tools called]
详细解答
📍 方案 A:前端直接调用(推荐用于公开搜索)
流程:
// 在店铺前端页面(买家浏览器中)
const response = await fetch('https://your-domain.com/api/search/products', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: "蓝牙耳机",
tenant: "tenant_47167113-1", // 店铺标识
size: 24,
filters: {},
facets: ['product_type', 'vendor']
})
});
你的搜索 API 需要:
- 允许跨域访问(CORS): ```python # Python FastAPI 示例 from fastapi.middleware.cors import CORSMiddleware
app.add_middleware( CORSMiddleware, allow_origins=[""], # 或指定店匠域名白名单 allow_credentials=True, allow_methods=["POST"], allow_headers=[""], )
2. **根据 store_id 隔离数据**:
```python
@app.post("/api/search/products")
async def search(request: SearchRequest):
# 从 tenant 参数提取 tenant_id
tenant_id = extract_tenant_id(request.tenant)
# 使用租户专属索引
index_name = f"shoplazza_products_{tenant_id}"
# 执行搜索
results = es_client.search(index=index_name, body=query)
return results
- 不需要 OAuth Token 认证(因为是公开查询)
📍 方案 B:通过 Java 后端中转(更安全)
流程:
买家浏览器 → Java后端(/api/search/products?storeId=xxx) → Python搜索服务 → ES
Java 后端代码:
@RestController
@RequestMapping("/api/search")
public class SearchController {
@PostMapping("/products")
public ResponseEntity<SearchResponse> search(
@RequestParam String storeId, // 从URL参数获取店铺ID
@RequestBody SearchRequest request) {
// 1. 验证店铺ID(可选:检查域名白名单)
ShopConfig shop = shopConfigMapper.selectByStoreId(storeId);
if (shop == null) {
return ResponseEntity.notFound().build();
}
// 2. 添加租户隔离参数
request.setTenant("tenant_" + shop.getTenantId());
// 3. 调用 Python 搜索服务
SearchResponse response = restTemplate.postForObject(
"http://localhost:6002/search/",
request,
SearchResponse.class
);
// 4. 记录搜索日志
searchLogService.logSearch(shop.getId(), request.getQuery(), response.getTotal());
return ResponseEntity.ok(response);
}
}
前端调用(带 store_id):
const response = await fetch(
`https://your-domain.com/api/search/products?storeId=${config.storeId}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: "蓝牙耳机",
size: 24,
filters: {},
facets: ['product_type', 'vendor']
})
}
);
🔐 OAuth 认证在整个系统中的位置
graph TB
subgraph "1. 商家安装阶段(使用OAuth)"
A[商家安装APP] --> B[OAuth授权]
B --> C[获取Access Token]
C --> D[存储Token到数据库]
end
subgraph "2. 数据准备阶段(使用OAuth Token)"
D --> E[定时任务启动]
E --> F[使用Token调用店匠API]
F --> G[拉取商品/订单数据]
G --> H[建立ES索引]
end
subgraph "3. 买家搜索阶段(不需要OAuth)"
I[买家访问店铺] --> J[输入搜索词]
J --> K[前端JS直接调用搜索API]
K --> L[搜索ES索引]
L --> M[返回结果]
end
H -.索引建立后.-> L
关键理解:
- OAuth Token = 你的后端 ↔ 店匠 Admin API(拉数据用)
- 前端搜索 = 买家浏览器 ↔ 你的搜索 API(不需要 OAuth)
✅ 你需要做的事情
1. 搜索 API 设计
当前你的 Python 搜索服务应该已经支持:
POST http://your-domain:6002/search/
Content-Type: application/json
{
"query": "蓝牙耳机",
"tenant": "tenant_1", // 重要!用于隔离不同店铺
"size": 20,
"filters": {},
"facets": ["product_type", "vendor"]
}
2. CORS 配置(如果前端直接调用)
在 Python FastAPI 服务中添加:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://*.myshoplaza.com", # 店匠域名
"https://your-domain.com"
],
allow_methods=["POST", "GET"],
allow_headers=["*"],
)
3. 店铺标识传递
在前端 Liquid 模板中获取店铺域名:
<script>
window.AI_SEARCH_CONFIG = {
storeId: "{{ shop.domain }}", // 店匠自动注入
apiEndpoint: "https://your-domain.com/api/search/products"
};
</script>
4. 安全性考虑
- ✅ 租户隔离:根据
tenant参数查询不同索引 - ✅ 域名白名单:只允许店匠域名调用
- ✅ 速率限制:防止恶意请求
- ❌ 不需要在每次搜索时验证 OAuth Token
🎯 总结
- OAuth 只用于后台数据同步,不用于前端搜索
- 前端搜索直接调用你的公开 API,通过
storeId参数隔离数据 - 你的搜索接口可以是无认证的,但必须做好租户隔离
- 推荐方案:前端 → 你的 Java 后端 → Python 搜索服务(便于日志统计和安全控制)
有其他疑问吗?