| 110 | |
| 111 | // 包装Netlify Functions为Express路由 |
| 112 | function wrapNetlifyFunction(handler) { |
| 113 | return async (req, res) => { |
| 114 | try { |
| 115 | const headers = Object.assign({}, req.headers); |
| 116 | // 仅在客户端未提供密钥时注入内部密钥(避免覆盖) |
| 117 | if (INTERNAL_FUNCTION_KEY && !headers['x-esim-key'] && !headers['x-app-key']) { |
| 118 | headers['x-esim-key'] = INTERNAL_FUNCTION_KEY; |
| 119 | } |
| 120 | const event = { |
| 121 | httpMethod: req.method, |
| 122 | headers, |
| 123 | body: JSON.stringify(req.body), |
| 124 | queryStringParameters: req.query |
| 125 | }; |
| 126 | |
| 127 | const context = {}; |
| 128 | const result = await handler.handler(event, context); |
| 129 | |
| 130 | res.status(result.statusCode); |
| 131 | |
| 132 | if (result.headers) { |
| 133 | Object.entries(result.headers).forEach(([key, value]) => { |
| 134 | res.set(key, value); |
| 135 | }); |
| 136 | } |
| 137 | |
| 138 | if (result.body) { |
| 139 | const body = typeof result.body === 'string' ? result.body : JSON.stringify(result.body); |
| 140 | res.send(body); |
| 141 | } else { |
| 142 | res.end(); |
| 143 | } |
| 144 | } catch (error) { |
| 145 | console.error('API Error:', error); |
| 146 | res.status(500).json({ |
| 147 | error: 'Internal Server Error', |
| 148 | message: error.message |
| 149 | }); |
| 150 | } |
| 151 | }; |
| 152 | } |
| 153 | |
| 154 | // API端点(同时挂 /.netlify/functions/* 与 /bff/*,本地模拟 Edge BFF 代理) |
| 155 | const functionRoutes = [ |