feat: 实现减脂体重管理App完整功能
- 实现拍照识别食物功能(集成大语言模型视觉能力) - 实现智能对话功能(集成大语言模型流式输出) - 实现食物记录和卡路里管理功能 - 实现体重记录和统计功能 - 实现健康数据管理页面 - 配置数据库表结构(用户、食物记录、体重记录) - 实现Express后端API路由 - 配置Tab导航和前端页面 - 采用健康运动配色方案
This commit is contained in:
121
client/metro.config.js
Normal file
121
client/metro.config.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const { getDefaultConfig } = require('expo/metro-config');
|
||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||
const connect = require('connect');
|
||||
|
||||
const config = getDefaultConfig(__dirname);
|
||||
|
||||
// 安全地获取 Expo 的默认排除列表
|
||||
const existingBlockList = [].concat(config.resolver.blockList || []);
|
||||
|
||||
config.resolver.blockList = [
|
||||
...existingBlockList,
|
||||
/.*\/\.expo\/.*/, // Expo 的缓存和构建产物目录
|
||||
|
||||
// 1. 原生代码 (Java/C++/Objective-C)
|
||||
/.*\/react-native\/ReactAndroid\/.*/,
|
||||
/.*\/react-native\/ReactCommon\/.*/,
|
||||
|
||||
// 2. 纯开发和调试工具
|
||||
// 这些工具只在开发电脑上运行,不会被打包到应用中
|
||||
/.*\/@typescript-eslint\/eslint-plugin\/.*/,
|
||||
|
||||
// 3. 构建时数据
|
||||
// 这个数据库只在打包过程中使用,应用运行时不需要
|
||||
/.*\/caniuse-lite\/data\/.*/,
|
||||
|
||||
// 4. 通用规则
|
||||
/.*\/__tests__\/.*/, // 排除所有测试目录
|
||||
/.*\.git\/.*/, // 排除 Git 目录
|
||||
];
|
||||
|
||||
const BACKEND_TARGET = 'http://localhost:9091';
|
||||
|
||||
const apiProxy = createProxyMiddleware({
|
||||
target: BACKEND_TARGET,
|
||||
changeOrigin: true,
|
||||
logLevel: 'debug',
|
||||
proxyTimeout: 86400000,
|
||||
onProxyReq: (proxyReq, req) => {
|
||||
const accept = req.headers.accept || '';
|
||||
if (accept.includes('text/event-stream')) {
|
||||
proxyReq.setHeader('accept-encoding', 'identity');
|
||||
}
|
||||
},
|
||||
onProxyRes: (proxyRes, req, res) => {
|
||||
const contentType = proxyRes.headers['content-type'] || '';
|
||||
if (contentType.includes('text/event-stream') || contentType.includes('application/stream')) {
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.setHeader('Connection', 'keep-alive');
|
||||
res.setHeader('X-Accel-Buffering', 'no');
|
||||
if (typeof res.flushHeaders === 'function') {
|
||||
try { res.flushHeaders(); } catch {}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const streamProxy = createProxyMiddleware({
|
||||
target: BACKEND_TARGET,
|
||||
changeOrigin: true,
|
||||
logLevel: 'debug',
|
||||
ws: true,
|
||||
proxyTimeout: 86400000,
|
||||
onProxyReq: (proxyReq, req) => {
|
||||
const upgrade = req.headers.upgrade;
|
||||
const accept = req.headers.accept || '';
|
||||
if (upgrade && upgrade.toLowerCase() === 'websocket') {
|
||||
proxyReq.setHeader('Connection', 'upgrade');
|
||||
proxyReq.setHeader('Upgrade', req.headers.upgrade);
|
||||
} else if (accept.includes('text/event-stream')) {
|
||||
proxyReq.setHeader('accept-encoding', 'identity');
|
||||
proxyReq.setHeader('Connection', 'keep-alive');
|
||||
}
|
||||
},
|
||||
onProxyRes: (proxyRes, req, res) => {
|
||||
const contentType = proxyRes.headers['content-type'] || '';
|
||||
if (contentType.includes('text/event-stream') || contentType.includes('application/stream')) {
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.setHeader('Connection', 'keep-alive');
|
||||
res.setHeader('X-Accel-Buffering', 'no');
|
||||
if (typeof res.flushHeaders === 'function') {
|
||||
try { res.flushHeaders(); } catch {}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const shouldProxyToBackend = (url) => {
|
||||
if (!url) return false;
|
||||
if (/^\/api\/v\d+\//.test(url)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const isWebSocketRequest = (req) =>
|
||||
!!(req.headers.upgrade && req.headers.upgrade.toLowerCase() === 'websocket');
|
||||
const isSSERequest = (req) => {
|
||||
const accept = req.headers.accept || '';
|
||||
return accept.includes('text/event-stream');
|
||||
};
|
||||
|
||||
config.server = {
|
||||
...config.server,
|
||||
enhanceMiddleware: (metroMiddleware, metroServer) => {
|
||||
return connect()
|
||||
.use((req, res, next) => {
|
||||
if (shouldProxyToBackend(req.url)) {
|
||||
console.log(`[Metro Proxy] Forwarding ${req.method} ${req.url}`);
|
||||
|
||||
if (isWebSocketRequest(req) || isSSERequest(req)) {
|
||||
return streamProxy(req, res, next);
|
||||
}
|
||||
return apiProxy(req, res, next);
|
||||
}
|
||||
next();
|
||||
})
|
||||
.use(metroMiddleware);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
Reference in New Issue
Block a user