Showing
17 changed files
with
224 additions
and
151 deletions
@@ -21,6 +21,10 @@ export function createApp(context) { | @@ -21,6 +21,10 @@ export function createApp(context) { | ||
21 | const app = new Vue({ | 21 | const app = new Vue({ |
22 | router, | 22 | router, |
23 | store, | 23 | store, |
24 | + errorCaptured(e) { | ||
25 | + console.log('errorCaptured', e); | ||
26 | + return false; | ||
27 | + }, | ||
24 | render: h => h(App) | 28 | render: h => h(App) |
25 | }); | 29 | }); |
26 | 30 |
@@ -2,7 +2,6 @@ const api = global.yoho.API; | @@ -2,7 +2,6 @@ const api = global.yoho.API; | ||
2 | const service = global.yoho.ServiceAPI; | 2 | const service = global.yoho.ServiceAPI; |
3 | const checkParams = require('../../utils/check-params'); | 3 | const checkParams = require('../../utils/check-params'); |
4 | const apiMaps = require('../../config/api-map'); | 4 | const apiMaps = require('../../config/api-map'); |
5 | -const _ = require('lodash'); | ||
6 | 5 | ||
7 | const NOT_FOUND_API_MAP = { | 6 | const NOT_FOUND_API_MAP = { |
8 | code: 400, | 7 | code: 400, |
@@ -13,30 +12,24 @@ const checkApiMap = url => { | @@ -13,30 +12,24 @@ const checkApiMap = url => { | ||
13 | }; | 12 | }; |
14 | const request = async({url, method, reqParams, context}) => { | 13 | const request = async({url, method, reqParams, context}) => { |
15 | const apiInfo = checkApiMap(url); | 14 | const apiInfo = checkApiMap(url); |
15 | + const {env, user} = context; | ||
16 | 16 | ||
17 | if (!apiInfo) { | 17 | if (!apiInfo) { |
18 | return Promise.reject(NOT_FOUND_API_MAP); | 18 | return Promise.reject(NOT_FOUND_API_MAP); |
19 | } | 19 | } |
20 | - try { | ||
21 | if (!apiInfo.service) { | 20 | if (!apiInfo.service) { |
22 | Object.assign(reqParams, { | 21 | Object.assign(reqParams, { |
23 | - uid: { | 22 | + uid: (user && user.uid) ? { |
24 | toString: () => { | 23 | toString: () => { |
25 | - return context.user.uid || 0; | ||
26 | - }, | ||
27 | - sessionKey: context.user.sessionKey, | ||
28 | - appSessionType: context.user.appSessionType | 24 | + return user.uid; |
29 | }, | 25 | }, |
26 | + sessionKey: user.sessionKey, | ||
27 | + appSessionType: user.appSessionType | ||
28 | + } : 1, | ||
30 | method: apiInfo.api, | 29 | method: apiInfo.api, |
31 | - sessionKey: context.user.sessionKey, | ||
32 | - appVersion: context.user.appVersion | ||
33 | }); | 30 | }); |
34 | } | 31 | } |
35 | - if (_.has(apiInfo, 'params.uid') && | ||
36 | - apiInfo.params.uid.require !== false && | ||
37 | - reqParams.uid === 0) { // 如果接口uid是必须的但是有没有传入uid则直接返回空对象 | ||
38 | - return Promise.resolve({}); | ||
39 | - } | 32 | + |
40 | const params = checkParams.getParams(reqParams, apiInfo); | 33 | const params = checkParams.getParams(reqParams, apiInfo); |
41 | const cache = method.toLowerCase() !== 'get' ? false : apiInfo.cache; | 34 | const cache = method.toLowerCase() !== 'get' ? false : apiInfo.cache; |
42 | 35 | ||
@@ -45,8 +38,9 @@ const request = async({url, method, reqParams, context}) => { | @@ -45,8 +38,9 @@ const request = async({url, method, reqParams, context}) => { | ||
45 | cache: cache, | 38 | cache: cache, |
46 | code: 200, | 39 | code: 200, |
47 | headers: { | 40 | headers: { |
48 | - 'X-YOHO-IP': context.env.clientIp, | ||
49 | - 'X-Forwarded-For': context.env.clientIp | 41 | + 'X-YOHO-IP': env.clientIp, |
42 | + 'X-Forwarded-For': env.clientIp, | ||
43 | + 'User-Agent': 'yoho/nodejs' | ||
50 | } | 44 | } |
51 | }); | 45 | }); |
52 | } else { | 46 | } else { |
@@ -54,17 +48,12 @@ const request = async({url, method, reqParams, context}) => { | @@ -54,17 +48,12 @@ const request = async({url, method, reqParams, context}) => { | ||
54 | code: 200, | 48 | code: 200, |
55 | cache: cache, | 49 | cache: cache, |
56 | headers: { | 50 | headers: { |
57 | - 'X-YOHO-IP': context.env.clientIp, | ||
58 | - 'X-Forwarded-For': context.env.clientIp | 51 | + 'X-YOHO-IP': env.clientIp, |
52 | + 'X-Forwarded-For': env.clientIp, | ||
53 | + 'User-Agent': 'yoho/nodejs' | ||
59 | } | 54 | } |
60 | }); | 55 | }); |
61 | } | 56 | } |
62 | - } catch (e) { | ||
63 | - return Promise.reject({ | ||
64 | - code: 400, | ||
65 | - message: `create api:${e}` | ||
66 | - }); | ||
67 | - } | ||
68 | }; | 57 | }; |
69 | 58 | ||
70 | export const createApi = context => { | 59 | export const createApi = context => { |
1 | import {createApp} from './app'; | 1 | import {createApp} from './app'; |
2 | -import _ from 'lodash/core'; | 2 | +import {get} from 'lodash'; |
3 | + | ||
3 | import { | 4 | import { |
4 | SET_ENV, | 5 | SET_ENV, |
5 | - INIT_ROUTE_CHANGE | ||
6 | } from 'store/yoho/types'; | 6 | } from 'store/yoho/types'; |
7 | +const sender = global.yoho.apmSender; | ||
8 | +const logger = global.yoho.logger; | ||
9 | + | ||
10 | +const catchError = (err, context) => { | ||
11 | + logger.error(`[catchError], ${err}`); | ||
12 | + setImmediate(() => { | ||
13 | + try { | ||
14 | + sender.addMessage({ | ||
15 | + measurement: 'error-report', | ||
16 | + tags: { | ||
17 | + app: 'yoho-app', // 应用名称 | ||
18 | + hostname: context.hostname, | ||
19 | + type: 'server', | ||
20 | + route: context.route, // 请求路由 | ||
21 | + uid: get(context, 'user.uid', 0), | ||
22 | + udid: context.udid, | ||
23 | + code: err.code || 500, | ||
24 | + path: context.path, | ||
25 | + url: encodeURIComponent(context.url), | ||
26 | + ip: context.env.clientIp | ||
27 | + }, | ||
28 | + fields: { | ||
29 | + message: err.message, | ||
30 | + stack: err.stack, | ||
31 | + useragent: context.ua | ||
32 | + } | ||
33 | + }); | ||
34 | + } catch (error) { | ||
35 | + logger.error(error); | ||
36 | + } | ||
37 | + }); | ||
38 | +}; | ||
7 | 39 | ||
8 | export default context => { | 40 | export default context => { |
9 | return new Promise((resolve, reject) => { | 41 | return new Promise((resolve, reject) => { |
10 | const {app, router, store} = createApp(context); | 42 | const {app, router, store} = createApp(context); |
11 | - const {url} = context; | 43 | + const {url, env} = context; |
12 | 44 | ||
13 | - const route = router.resolve(url).route; | ||
14 | - | ||
15 | - // if (url !== route.fullPath) { | ||
16 | - // return reject({code: 500, message: 'url not matched', url: route.fullPath}); | ||
17 | - // } | ||
18 | - store.commit(SET_ENV, context.env); | 45 | + store.commit(SET_ENV, env); |
19 | router.push(url); | 46 | router.push(url); |
20 | router.onReady(() => { | 47 | router.onReady(() => { |
21 | - try { | ||
22 | const matched = router.getMatchedComponents(); | 48 | const matched = router.getMatchedComponents(); |
23 | 49 | ||
24 | - if (!matched.length) { | ||
25 | - reject({code: 404}); | 50 | + if (matched.some(m => !m)) { |
51 | + catchError(new Error('导航组件为空'), context); | ||
52 | + router.push({name: 'error.500'}); | ||
53 | + return resolve(app); | ||
26 | } | 54 | } |
27 | - const routes = []; | ||
28 | - const rootRoute = _.find(router.options.routes, r => r.meta && r.meta.root); | ||
29 | - | ||
30 | - if (rootRoute) { | ||
31 | - routes.push({ | ||
32 | - name: rootRoute.name, | ||
33 | - fullPath: rootRoute.path | ||
34 | - }); | ||
35 | - } | ||
36 | - | ||
37 | - if (route.name !== 'channel.home') { | ||
38 | - routes.push({ | ||
39 | - name: route.name, | ||
40 | - fullPath: route.fullPath | ||
41 | - }); | 55 | + if (!matched.length) { |
56 | + return reject({code: 404, message: ''}); | ||
42 | } | 57 | } |
43 | 58 | ||
44 | - store.commit(INIT_ROUTE_CHANGE, {routes}); | ||
45 | Promise.all(matched.map(({asyncData}) => | 59 | Promise.all(matched.map(({asyncData}) => |
46 | asyncData && asyncData({store, router: router.currentRoute}))) | 60 | asyncData && asyncData({store, router: router.currentRoute}))) |
47 | .then(() => { | 61 | .then(() => { |
48 | context.state = store.state; | 62 | context.state = store.state; |
49 | - resolve(app); | ||
50 | - }).catch((e) => { | ||
51 | - reject({ | ||
52 | - code: 500, | ||
53 | - message: e.stack || e.toString() | 63 | + return resolve(app); |
64 | + }).catch(e => { | ||
65 | + catchError(e, context); | ||
66 | + return resolve(app); | ||
54 | }); | 67 | }); |
55 | }); | 68 | }); |
56 | - } catch (e) { | ||
57 | - reject({ | ||
58 | - code: 500, | ||
59 | - message: e.stack || e.toString() | 69 | + |
70 | + router.onError(e => { | ||
71 | + catchError(e, context); | ||
72 | + router.push({name: 'error.500'}); | ||
73 | + return resolve(app); | ||
60 | }); | 74 | }); |
61 | - } | ||
62 | - }, reject); | ||
63 | }); | 75 | }); |
64 | }; | 76 | }; |
apps/pages/common/error/404.vue
0 → 100644
apps/pages/common/error/500.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="err-500"> | ||
3 | + 500 | ||
4 | + <NotFound></NotFound> | ||
5 | + </div> | ||
6 | +</template> | ||
7 | + | ||
8 | +<script> | ||
9 | +export default { | ||
10 | + name: 'Error', | ||
11 | + created() { | ||
12 | + console.log('400 created') | ||
13 | + }, | ||
14 | + mounted() { | ||
15 | + console.log('400 mounted') | ||
16 | + }, | ||
17 | + components: {NotFound: () => import('./404')} | ||
18 | +} | ||
19 | +</script> | ||
20 | + | ||
21 | +<style> | ||
22 | + | ||
23 | +</style> |
apps/pages/common/error/index.js
0 → 100644
apps/pages/common/index.js
0 → 100644
@@ -5,7 +5,7 @@ import routes from '../pages'; | @@ -5,7 +5,7 @@ import routes from '../pages'; | ||
5 | Vue.use(Router); | 5 | Vue.use(Router); |
6 | 6 | ||
7 | export function createRouter() { | 7 | export function createRouter() { |
8 | - return new Router({ | 8 | + const route = new Router({ |
9 | mode: 'history', | 9 | mode: 'history', |
10 | routes, | 10 | routes, |
11 | scrollBehavior(to, from, savedPosition) { | 11 | scrollBehavior(to, from, savedPosition) { |
@@ -16,4 +16,13 @@ export function createRouter() { | @@ -16,4 +16,13 @@ export function createRouter() { | ||
16 | } | 16 | } |
17 | } | 17 | } |
18 | }); | 18 | }); |
19 | + | ||
20 | + route.beforeEach((to, from, next) => { | ||
21 | + if (!to.matched.length) { | ||
22 | + return next({name: 'error.404'}); | ||
23 | + } | ||
24 | + next(); | ||
25 | + }); | ||
26 | + | ||
27 | + return route; | ||
19 | } | 28 | } |
apps/utils/error-handler.js
0 → 100644
@@ -66,9 +66,9 @@ exports.createApp = async(app) => { | @@ -66,9 +66,9 @@ exports.createApp = async(app) => { | ||
66 | app.use(userMiddleware); | 66 | app.use(userMiddleware); |
67 | app.use(ssrApiMiddleware); | 67 | app.use(ssrApiMiddleware); |
68 | 68 | ||
69 | - app.use(ssrRouteMiddleware); | 69 | + app.use(ssrRouteMiddleware.routers); |
70 | 70 | ||
71 | - app.all('*', errorMiddleware.notFound); // 404 | 71 | + app.all('*', ssrRouteMiddleware.ssrRender); // 404 |
72 | 72 | ||
73 | // YOHO 后置中间件 | 73 | // YOHO 后置中间件 |
74 | app.use(errorMiddleware.serverError); | 74 | app.use(errorMiddleware.serverError); |
1 | -/** | ||
2 | - * 404 错误 | ||
3 | - * @return {[type]} | ||
4 | - */ | ||
5 | const logger = global.yoho.logger; | 1 | const logger = global.yoho.logger; |
6 | 2 | ||
7 | -exports.notFound = (req, res) => { | ||
8 | - res.status(404); | ||
9 | - | ||
10 | - if (req.xhr) { | ||
11 | - return res.json({ | ||
12 | - code: 404, | ||
13 | - message: '抱歉,页面不存在!' | ||
14 | - }); | ||
15 | - } | ||
16 | - | ||
17 | - return res.render('error/404', { | ||
18 | - module: 'common', | ||
19 | - page: 'error', | ||
20 | - title: '页面不存在 | BLK | 潮流购物逛不停', | ||
21 | - noLocalCSS: true | ||
22 | - }); | ||
23 | -}; | ||
24 | - | ||
25 | /** | 3 | /** |
26 | * 服务器错误 | 4 | * 服务器错误 |
27 | * @return {[type]} | 5 | * @return {[type]} |
28 | */ | 6 | */ |
29 | -exports.serverError = (err, req, res, next) => { | 7 | +exports.serverError = (err, req, res, next) => { // eslint-disable-line |
30 | logger.error(`error at path: ${req.url}`); | 8 | logger.error(`error at path: ${req.url}`); |
31 | - logger.error(err); | 9 | + logger.error(`${req.url},${err}`); |
32 | 10 | ||
33 | - if (!res.headersSent) { | ||
34 | res.status(err.code || 500); | 11 | res.status(err.code || 500); |
35 | 12 | ||
36 | if (req.xhr) { | 13 | if (req.xhr) { |
@@ -40,12 +17,5 @@ exports.serverError = (err, req, res, next) => { | @@ -40,12 +17,5 @@ exports.serverError = (err, req, res, next) => { | ||
40 | }); | 17 | }); |
41 | } | 18 | } |
42 | 19 | ||
43 | - return res.render('error/500', { | ||
44 | - module: 'common', | ||
45 | - page: 'error', | ||
46 | - title: '服务器错误 | BLK | 潮流购物逛不停', | ||
47 | - noLocalCSS: true | ||
48 | - }); | ||
49 | - } | ||
50 | - next(err); | 20 | + return res.send('服务器开小差了~'); |
51 | }; | 21 | }; |
@@ -13,13 +13,13 @@ module.exports = async(req, res, next) => { | @@ -13,13 +13,13 @@ module.exports = async(req, res, next) => { | ||
13 | 13 | ||
14 | if (!apiInfo.service) { | 14 | if (!apiInfo.service) { |
15 | baseParams = { | 15 | baseParams = { |
16 | - uid: { | 16 | + uid: (req.user && req.user.uid) ? { |
17 | toString: () => { | 17 | toString: () => { |
18 | return req.user.uid || 0; | 18 | return req.user.uid || 0; |
19 | }, | 19 | }, |
20 | sessionKey: req.user.sessionKey, | 20 | sessionKey: req.user.sessionKey, |
21 | appSessionType: req.user.appSessionType | 21 | appSessionType: req.user.appSessionType |
22 | - }, | 22 | + } : 0, |
23 | method: apiInfo.api | 23 | method: apiInfo.api |
24 | }; | 24 | }; |
25 | } | 25 | } |
1 | const fs = require('fs'); | 1 | const fs = require('fs'); |
2 | const path = require('path'); | 2 | const path = require('path'); |
3 | const url = require('url'); | 3 | const url = require('url'); |
4 | -const sourceMap = require('source-map'); | ||
5 | const _ = require('lodash'); | 4 | const _ = require('lodash'); |
5 | +const os = require('os'); | ||
6 | const md5 = require('yoho-md5'); | 6 | const md5 = require('yoho-md5'); |
7 | const pkg = require('../../package.json'); | 7 | const pkg = require('../../package.json'); |
8 | const routes = require('../../config/ssr-routes'); | 8 | const routes = require('../../config/ssr-routes'); |
9 | const redis = require('../../utils/redis'); | 9 | const redis = require('../../utils/redis'); |
10 | +const routeEncode = require('../../utils/route-encode'); | ||
10 | const {createBundleRenderer} = require('vue-server-renderer'); | 11 | const {createBundleRenderer} = require('vue-server-renderer'); |
11 | const logger = global.yoho.logger; | 12 | const logger = global.yoho.logger; |
12 | const config = global.yoho.config; | 13 | const config = global.yoho.config; |
13 | 14 | ||
14 | -const REG_STACK = /at ([^:]+):(\d+):(\d+)/; | ||
15 | - | ||
16 | const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV; | 15 | const isDev = process.env.NODE_ENV === 'development' || !process.env.NODE_ENV; |
17 | 16 | ||
18 | let renderer; | 17 | let renderer; |
@@ -41,11 +40,26 @@ const getContext = (req) => { | @@ -41,11 +40,26 @@ const getContext = (req) => { | ||
41 | isiOS: req.yoho.isiOS, | 40 | isiOS: req.yoho.isiOS, |
42 | isAndroid: req.yoho.isAndroid, | 41 | isAndroid: req.yoho.isAndroid, |
43 | isYohoApp: req.yoho.isYohoApp, | 42 | isYohoApp: req.yoho.isYohoApp, |
44 | - clientIp: req.yoho.clientIp | ||
45 | - } | 43 | + clientIp: req.yoho.clientIp, |
44 | + }, | ||
45 | + ua: req.get('user-agent'), | ||
46 | + hostname: os.hostname(), | ||
47 | + route: `[${req.method}]${_.get(req, 'route.path', '')}`, // 请求路由 | ||
48 | + udid: _.get(req, 'cookies.udid', 'yoho'), | ||
49 | + path: `[${req.method}]${routeEncode.getRouter(req)}`, | ||
46 | }; | 50 | }; |
47 | }; | 51 | }; |
48 | 52 | ||
53 | +const handlerError = (err = {}, req, res, next) => { | ||
54 | + if (err.code === 404) { | ||
55 | + return res.redirect('/error/404'); | ||
56 | + } else if (err.code === 500) { | ||
57 | + return res.redirect('/error/500'); | ||
58 | + } | ||
59 | + console.log(err) | ||
60 | + return next(err); | ||
61 | +}; | ||
62 | + | ||
49 | const getCacheKey = (urlPath, cackeKey = '') => { | 63 | const getCacheKey = (urlPath, cackeKey = '') => { |
50 | const urlObj = url.parse(urlPath); | 64 | const urlObj = url.parse(urlPath); |
51 | 65 | ||
@@ -54,37 +68,11 @@ const getCacheKey = (urlPath, cackeKey = '') => { | @@ -54,37 +68,11 @@ const getCacheKey = (urlPath, cackeKey = '') => { | ||
54 | .replace('$params', urlObj.query)); | 68 | .replace('$params', urlObj.query)); |
55 | }; | 69 | }; |
56 | 70 | ||
57 | -const parseError = async({stack = ''}) => { | ||
58 | - try { | ||
59 | - const splits = stack.split('\n'); | ||
60 | - const lastError = splits.map(str => { | ||
61 | - const match = str.match(REG_STACK); | ||
62 | - | ||
63 | - if (match) { | ||
64 | - return {file: match[1], line: parseInt(match[2], 10), column: parseInt(match[3], 10)}; | ||
65 | - } | ||
66 | - return false; | ||
67 | - }).find(match => match); | ||
68 | - | ||
69 | - if (lastError && lastError.file) { | ||
70 | - const consumer = await new sourceMap.SourceMapConsumer(serverBundle.maps[lastError.file]); | ||
71 | - | ||
72 | - const origin = consumer.originalPositionFor({ | ||
73 | - line: lastError.line, | ||
74 | - column: 342 | ||
75 | - }); | ||
76 | - | ||
77 | - console.log(origin); | ||
78 | - } | ||
79 | - } catch (error) { | ||
80 | - logger.error(error); | ||
81 | - } | ||
82 | -}; | ||
83 | - | ||
84 | const render = (route) => { | 71 | const render = (route) => { |
85 | return async(req, res, next) => { | 72 | return async(req, res, next) => { |
73 | + try { | ||
86 | res.setHeader('X-YOHO-Version', pkg.version); | 74 | res.setHeader('X-YOHO-Version', pkg.version); |
87 | - const ck = getCacheKey(req.url, route.cackeKey); | 75 | + const ck = route.cackeKey ? getCacheKey(req.url, route.cackeKey) : void 0; |
88 | 76 | ||
89 | if (config.useCache && route.cache && ck) { | 77 | if (config.useCache && route.cache && ck) { |
90 | const html = await redis.getAsync(ck); | 78 | const html = await redis.getAsync(ck); |
@@ -100,20 +88,23 @@ const render = (route) => { | @@ -100,20 +88,23 @@ const render = (route) => { | ||
100 | 88 | ||
101 | renderer.renderToString(context, (err, html) => { | 89 | renderer.renderToString(context, (err, html) => { |
102 | if (err) { | 90 | if (err) { |
103 | - parseError(err); | ||
104 | - return next(err.message); | 91 | + return handlerError(err, req, res, next); |
105 | } | 92 | } |
106 | if (config.useCache && route.cache && ck) { | 93 | if (config.useCache && route.cache && ck) { |
107 | redis.setex(ck, route.cacheTime || 60, html); | 94 | redis.setex(ck, route.cacheTime || 60, html); |
108 | } | 95 | } |
109 | return res.send(html); | 96 | return res.send(html); |
110 | }); | 97 | }); |
98 | + } catch (error) { | ||
99 | + return next(error); | ||
100 | + } | ||
111 | }; | 101 | }; |
112 | }; | 102 | }; |
113 | const devRender = (route) => { | 103 | const devRender = (route) => { |
114 | return async(req, res, next) => { | 104 | return async(req, res, next) => { |
105 | + try { | ||
115 | res.setHeader('X-YOHO-Version', pkg.version); | 106 | res.setHeader('X-YOHO-Version', pkg.version); |
116 | - const ck = getCacheKey(req.url, route.cackeKey); | 107 | + const ck = route.cackeKey ? getCacheKey(req.url, route.cackeKey) : void 0; |
117 | 108 | ||
118 | if (config.useCache && route.cache && ck) { | 109 | if (config.useCache && route.cache && ck) { |
119 | const html = await redis.getAsync(ck); | 110 | const html = await redis.getAsync(ck); |
@@ -132,19 +123,12 @@ const devRender = (route) => { | @@ -132,19 +123,12 @@ const devRender = (route) => { | ||
132 | process.removeListener('message', event); | 123 | process.removeListener('message', event); |
133 | if (msg.action === 'ssr_request') { | 124 | if (msg.action === 'ssr_request') { |
134 | if (msg.err) { | 125 | if (msg.err) { |
135 | - try { | ||
136 | - const err = JSON.parse(msg.err); | 126 | + let err = msg.err; |
137 | 127 | ||
138 | - if (err.code === 404) { | ||
139 | - return next(); | ||
140 | - } | ||
141 | - return next(err); | ||
142 | - } catch (e) { | ||
143 | - return next({ | ||
144 | - code: 500, | ||
145 | - message: msg.err | ||
146 | - }); | ||
147 | - } | 128 | + try { |
129 | + err = JSON.parse(msg.err); | ||
130 | + } catch (error) {} // eslint-disable-line | ||
131 | + return handlerError(err, req, res, next); | ||
148 | } | 132 | } |
149 | if (config.useCache && route.cache && ck) { | 133 | if (config.useCache && route.cache && ck) { |
150 | redis.setex(ck, route.cacheTime || 60, msg.html); | 134 | redis.setex(ck, route.cacheTime || 60, msg.html); |
@@ -154,6 +138,9 @@ const devRender = (route) => { | @@ -154,6 +138,9 @@ const devRender = (route) => { | ||
154 | }; | 138 | }; |
155 | 139 | ||
156 | process.on('message', event); | 140 | process.on('message', event); |
141 | + } catch (error) { | ||
142 | + return next(error); | ||
143 | + } | ||
157 | }; | 144 | }; |
158 | }; | 145 | }; |
159 | 146 | ||
@@ -165,4 +152,6 @@ _.each(routes, r => { | @@ -165,4 +152,6 @@ _.each(routes, r => { | ||
165 | } | 152 | } |
166 | }); | 153 | }); |
167 | 154 | ||
168 | -module.exports = router; | 155 | +exports.ssrRender = isDev ? devRender({}) : render({}); |
156 | + | ||
157 | +exports.routers = router; |
utils/route-encode.js
0 → 100644
1 | +const _ = require('lodash'); | ||
2 | +const crypto = global.yoho.crypto; | ||
3 | + | ||
4 | +function urlJoin(a, b) { | ||
5 | + if (_.endsWith(a, '/') && _.startsWith(b, '/')) { | ||
6 | + return a + b.substring(1, b.length); | ||
7 | + } else if (!_.endsWith(a, '/') && !_.startsWith(b, '/')) { | ||
8 | + return a + '/' + b; | ||
9 | + } else { | ||
10 | + return a + b; | ||
11 | + } | ||
12 | +} | ||
13 | + | ||
14 | +function _encode(str) { | ||
15 | + return encodeURIComponent(crypto.encryption(null, str)); | ||
16 | +} | ||
17 | + | ||
18 | +const encode = _.memoize(_encode); | ||
19 | + | ||
20 | +function getRouter(req) { | ||
21 | + let route = req.route ? req.route.path : ''; | ||
22 | + let appPath = req.app.mountpath; | ||
23 | + | ||
24 | + if (_.isArray(route) && route.length > 0) { | ||
25 | + route = route[0]; | ||
26 | + } | ||
27 | + | ||
28 | + let key = urlJoin(appPath, route.toString()); // route may be a regexp | ||
29 | + | ||
30 | + if (key) { | ||
31 | + return encode(key); | ||
32 | + } | ||
33 | + | ||
34 | + return ''; | ||
35 | +} | ||
36 | + | ||
37 | +module.exports.md = function(req, res, next) { | ||
38 | + function onRender() { | ||
39 | + res.locals._router = getRouter(req); | ||
40 | + } | ||
41 | + | ||
42 | + res.on('beforeRender', onRender); | ||
43 | + next(); | ||
44 | +}; | ||
45 | + | ||
46 | +module.exports.getRouter = getRouter; |
-
Please register or login to post a comment