调用Vision API Product Search提示缺失有效API密钥如何处理
报错根因
接口返回"message": "The request is missing a valid API key.",是因为请求没有携带合法鉴权信息。你下载的服务账号私钥JSON不能直接作为接口参数上传,需要先用它生成短期有效的访问令牌,再把令牌放到请求头里完成鉴权。
基础概念说明
- 官方文档里的curl是命令行HTTP请求工具,示例本质是标注清楚请求需要的四个核心要素:请求地址、请求方法、请求头、请求体,用Dart http库发请求时把四个要素对应填对就行。
- 服务账号鉴权流程:用本地存储的服务账号JSON,向Google OAuth2.0服务申请Access Token,之后调用业务接口时把Token放到
Authorization请求头中即可,不需要直接传JSON文件给业务接口。
参考截图
- 官方文档示例:
- 原有问题代码:
修正步骤
- 先在
pubspec.yaml添加官方鉴权库依赖,用来处理服务账号换Token的逻辑:
dependencies: http: ^1.1.0 googleapis_auth: ^1.4.1
- 把下载的服务账号JSON文件放到项目
assets目录下,在pubspec.yaml中配置好资产路径,不要把私钥内容硬编码在代码里。 - 替换原有请求代码,鉴权逻辑由官方库自动处理:
import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:googleapis_auth/auth_io.dart'; import 'package:flutter/services.dart' show rootBundle; Future<void> uploadProductSet() async { // 加载本地服务账号凭证 final serviceAccountData = json.decode( await rootBundle.loadString('assets/你的服务账号文件名.json') ); final credentials = ServiceAccountCredentials.fromJson(serviceAccountData); // 申请Vision API访问权限的令牌 const authScopes = ['https://www.googleapis.com/auth/cloud-platform']; final authClient = await clientViaServiceAccount(credentials, authScopes); // 组装请求参数 const projectId = 'estoOne'; const locationId = 'europe-west1'; final requestUrl = Uri.parse( 'https://vision.googleapis.com/v1/projects/$projectId/locations/$locationId/productSets' ); final requestBody = json.encode({ 'displayName': 'Product-Set-One', }); try { // 发送请求,authClient会自动在请求头注入合法的鉴权信息 final response = await authClient.post( requestUrl, headers: {'Content-Type': 'application/json'}, body: requestBody, ); print(response.body); } catch (e) { rethrow; } finally { authClient.close(); } }
注意事项
- Flutter客户端直接存放服务账号JSON有私钥泄露风险,生产环境建议把鉴权逻辑放到自有后端,客户端只调用后端接口,避免凭证泄露被恶意调用产生费用。
- 临时测试可以直接在Google Cloud控制台创建API Key,请求时在URL末尾拼接
?key=你的APIKey即可完成鉴权,但API Key权限管控粒度粗,不建议生产环境使用。 - 原代码存在拼写错误:
resoinseOne应为responseOne,且缺少Content-Type: application/json请求头,即使鉴权通过也可能触发参数格式错误。
内容的提问来源于stack exchange,提问作者Flutter Dev
相关产品推荐
相关产品推荐



