Cloud Run服务SSL证书不匹配导致Chrome扩展Fetch请求失败的排查及证书刷新方法咨询
Cloud Run服务SSL证书不匹配导致Chrome扩展Fetch请求失败的排查及证书刷新方法咨询
最近我碰到了一个棘手的问题:Chrome扩展里调用Google Cloud Run服务时,Fetch请求直接抛出TypeError: Failed to fetch错误。后来用curl直接测试服务端点,发现根源是SSL证书不匹配,报错信息如下:
curl: (60) SSL: no alternative certificate subject name matches target host name 'command-processor-[PROJECT_ID]-us-central1.run.app'
我的核心需求
让Chrome扩展的弹窗通过POST请求正常调用Cloud Run服务
已经排查验证过的内容
我逐一检查了这些可能的问题点,结果都没问题:
- Cloud Run服务部署完全成功,没有出现“容器启动失败”类的错误
- 扩展的
manifest.json已经正确配置了host_permissions:https://*.run.app/ - 扩展清单文件里也包含了
"downloads"权限 - 扩展Fetch请求里的URL和部署后的服务URL完全一致
看起来问题肯定出在Cloud Run服务本身的SSL证书配置或者映射上,但我很疑惑——这是Google默认分配的.run.app域名啊,怎么会出现证书不匹配的情况?
我想咨询的问题
- 为什么默认分配
.run.app域名的Cloud Run服务会出现SSL证书不匹配的问题? - 在Google Cloud控制台里,有哪些具体步骤可以调试这个问题?或者有没有办法强制刷新服务的SSL证书?
后端代码(index.js)
这是我用Cloud Functions Framework写的后端代码:
// index.js (Corrected for Google Cloud Functions Framework) const functions = require('@google-cloud/functions-framework'); const { google } = require('googleapis'); // This is the correct way to use cors with this framework const cors = require('cors')({ origin: true }); // IMPORTANT: Replace this with your actual API key if needed. const API_KEY = '**************'; // This is the single entry point for your Cloud Function functions.http("commandProcessor", (req, res) => { // The cors function handles the OPTIONS pre-flight request and then calls the callback. cors(req, res, async () => { try { // --- Route 1: Handle the new /summarize-chat endpoint --- if (req.path === '/summarize-chat') { if (req.method !== 'POST') { return res.status(405).send('Method Not Allowed'); } console.log("Handling request for /summarize-chat"); const transcript = req.body.transcript; if (!transcript) { return res.status(400).json({ error: 'No transcript provided.' }); } const summary = `### Chat Session Summary\n**Date:** ${new Date().toISOString()}\n\n**Raw Transcript:**\n---\n${transcript}\n---`; return res.status(200).json({ summary: summary }); } // --- Route 2: Handle all other requests as Drive commands (your original logic) --- console.log("Handling request for Drive command processor."); if (req.get('x-api-key') !== API_KEY) { console.error("Unauthorized request: API key missing or incorrect."); return res.status(401).send('Unauthorized'); } if (req.method !== 'POST') { return res.status(405).send('Method Not Allowed. Only POST is supported.'); } const commandObject = req.body; // ... (The rest of your original Drive command logic starts here and is unchanged) if (!commandObject || !commandObject.command || !commandObject.parameters) { console.error("Invalid command format received. Expected {command: 'CMD', parameters: [...]}."); return res.status(400).send("Invalid command format."); } const authHeader = req.get('Authorization'); let userAuthToken = null; if (authHeader && authHeader.startsWith('Bearer ')) { userAuthToken = authHeader.substring(7); } else { console.warn("No Bearer token provided by client. This command might fail if it requires user-specific Drive access."); } console.log(`Cloud Run: Received raw command object: ${JSON.stringify(commandObject)}`); console.log(`Cloud Run: Command extracted for switch: ${commandObject.command.toUpperCase()}`); let result; switch (commandObject.command.toUpperCase()) { case 'DRIVE_CREATE_PROJECT': result = await createProjectInDrive(commandObject.parameters[0], userAuthToken); break; // Add your other cases for DRIVE_CREATE_FILE, DRIVE_MOVE_FILE, etc. back in here default: result = { success: false, message: `Unknown Drive command: ${commandObject.command}.` }; break; } if (result.success) { res.status(200).json({ status: 'success', message: result.message, data: result.data }); } else { res.status(500).json({ status: 'error', message: result.message }); } } catch (error) { console.error('Unhandled error in function:', error); res.status(500).json({ status: 'error', message: `Internal server error: ${error.message}` }); } }); }); // --- All existing Google Drive helper functions remain here, unchanged --- async function getDriveClient(token) { // ... (your existing function) } async function createProjectInDrive(projectName, token) { // ... (your existing function) } // ... etc for all other helper functions.
Chrome扩展清单文件(manifest.json)
{ "manifest_version": 3, "name": "My Life AI Drive Extension", "version": "1.2", "description": "A private extension to allow My Life ...", "host_permissions": ["https://*.run.app/"], "permissions": ["downloads"] }
内容来源于stack exchange
相关产品推荐
相关产品推荐

