搜索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 需要:

  1. 允许跨域访问(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
  1. 不需要 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

🎯 总结

  1. OAuth 只用于后台数据同步,不用于前端搜索
  2. 前端搜索直接调用你的公开 API,通过 storeId 参数隔离数据
  3. 你的搜索接口可以是无认证的,但必须做好租户隔离
  4. 推荐方案:前端 → 你的 Java 后端 → Python 搜索服务(便于日志统计和安全控制)

有其他疑问吗?