'use strict'; const TaobaoAuth = require('./taobao-auth'); module.exports = function ({ accounts, wrinkleJobs, readBody, sendJson, handleAnalyze }) { const taobaoSessions = require('./taobao-session')({ session: accounts.taobaoSession }); return async function (req, res, pathname) { res.setHeader('Cache-Control', 'no-store'); // The cloud gateway requires its own envelope. H5 responses stay unchanged. const reply = (status, data) => sendJson(res, 200, { success: true, data: { ...data, http_status: status } }); if (req.method !== 'POST') return reply(405, { ok: false, message: '请求方法不支持' }); if (!accounts.sameOrigin(req)) return reply(403, { ok: false, message: '请求来源不匹配' }); try { const raw = (await readBody(req, pathname === '/api/taobao/photo' ? 70 * 1024 : 4096)).toString('utf8'); const body = JSON.parse(raw); if (!body || typeof body !== 'object' || Array.isArray(body)) return reply(400, { ok: false, message: '请求数据异常' }); if (pathname === '/api/taobao/challenge') { const challenge = taobaoSessions.challenge(req.socket.remoteAddress); return reply(challenge ? 200 : 429, challenge ? { ok: true, challenge } : { ok: false, message: '操作频繁,请稍后重试' }); } if (pathname === '/api/taobao/session') { if (body.consent !== true) return reply(400, { ok: false, message: '请先阅读并同意隐私协议' }); const identity = TaobaoAuth.verify(req.url, raw); if (!identity || !taobaoSessions.consume(body.challenge)) return reply(401, { ok: false, message: '淘宝身份校验失败,请重新授权登录' }); return reply(200, { ok: true, ...accounts.loginTaobao(identity.providerKey) }); } if (pathname === '/api/taobao/guest-session') { if (body.consent !== true) return reply(400, { ok: false, message: '请先阅读并同意隐私协议' }); if (!TaobaoAuth.verifyGateway(req.url, raw) || !taobaoSessions.consume(body.challenge)) { return reply(401, { ok: false, message: '游客会话校验失败,请重新开始' }); } const guest = accounts.loginTaobaoGuest(); return reply(guest ? 200 : 429, guest ? { ok: true, ...guest } : { ok: false, message: '操作频繁,请稍后再试' }); } const owner = accounts.taobaoSession(req); if (!owner) return reply(401, { ok: false, message: '检测会话已失效,请重新开始' }); if (pathname === '/api/taobao/me') { // A cached Bearer must not restore the previous Taobao account after // the host app switches accounts. Guests require a signed app gateway // but intentionally have no dependency on userInfo/open_id authorization. const identity = owner.kind === 'taobao_guest' ? null : TaobaoAuth.verify(req.url, raw); const matches = owner.kind === 'taobao_guest' ? !!TaobaoAuth.verifyGateway(req.url, raw) : !!identity && identity.providerKey === owner.provider_key; return reply(matches ? 200 : 401, matches ? { ok: true, user: { id: owner.id, kind: owner.kind } } : { ok: false, message: '淘宝账号状态已变化,请重新进入' }); } if (pathname === '/api/taobao/photo') { const { status, ...data } = taobaoSessions.upload(req, body); return reply(status, { ok: status === 200, ...data }); } if (pathname === '/api/taobao/skin-analyze') { // Start once and poll: cloud gateway requests have a maximum 10s timeout. const attempt = taobaoSessions.beginAnalysis(req, body, photos => new Promise(resolve => { const response = { setHeader() {}, writeHead() {}, end(text, cb) { resolve(JSON.parse(text)); if (cb) cb(); } }; handleAnalyze(req, response, true, { ...body, ...photos }, owner).catch(() => resolve({ ok: false, message: '检测服务暂不可用,请重试' })); })); return reply(attempt.status, { ok: attempt.status === 202, ...(attempt.job ? { job: attempt.job } : { message: attempt.message }) }); } if (pathname === '/api/taobao/analysis') { const result = taobaoSessions.result(req, body.job); return reply(result ? 200 : 404, result ? { ok: true, ...result } : { ok: false, message: owner.kind === 'taobao_guest' ? '本次检测任务已失效,请重新开始' : '检测任务已失效,请查看历史报告或重新检测' }); } if (pathname === '/api/taobao/reports') { if (owner.kind === 'taobao_guest') return reply(body.id ? 404 : 200, body.id ? { ok: false, message: '游客模式不保存历史报告' } : { ok: true, total: 0, items: [] }); if (!body.id) return reply(200, { ok: true, total: accounts.reports(owner.id).length, items: accounts.reports(owner.id) }); const report = accounts.ownedReport(owner.id, body.id); return reply(report ? 200 : 404, report ? { ok: true, report } : { ok: false, message: '报告不存在' }); } if (pathname === '/api/taobao/logout') { taobaoSessions.revoke(req); accounts.taobaoLogout(req); return reply(200, { ok: true }); } if (pathname === '/api/taobao/wrinkle-views') { const job = taobaoSessions.start(req, async () => { const views = await wrinkleJobs.run(owner, body.token); return views ? { ok: true, wrinkle_views: views } : { ok: false, message: '标注任务已失效' }; }); return reply(job ? 202 : 429, job ? { ok: true, job } : { ok: false, message: '服务繁忙,请稍后再试' }); } return reply(404, { ok: false, message: '接口不存在' }); } catch (e) { const status = e.message === 'TOO_LARGE' ? 413 : e instanceof SyntaxError ? 400 : 500; return reply(status, { ok: false, message: status === 413 ? '请求数据过大' : status === 400 ? '请求数据异常' : '服务暂不可用,请稍后再试' }); } }; };