Merge branch 'feature/tdk'
Showing
11 changed files
with
182 additions
and
27 deletions
@@ -35,6 +35,10 @@ const pkg = require('./package.json'); | @@ -35,6 +35,10 @@ const pkg = require('./package.json'); | ||
35 | const app = express(); | 35 | const app = express(); |
36 | const helpers = global.yoho.helpers; | 36 | const helpers = global.yoho.helpers; |
37 | 37 | ||
38 | +// tdk | ||
39 | +global.yoho.redis = require('./doraemon/middleware/redis'); | ||
40 | +const tdk = require('./utils/getTDK'); | ||
41 | + | ||
38 | // NOTE: 这里修改了图片质量的参数 | 42 | // NOTE: 这里修改了图片质量的参数 |
39 | helpers.image = _.flow(helpers.image, fp.replace(/\/quality\/\d*$/, '/quality/90')); | 43 | helpers.image = _.flow(helpers.image, fp.replace(/\/quality\/\d*$/, '/quality/90')); |
40 | 44 | ||
@@ -163,6 +167,24 @@ app.use((req, res, next) => { | @@ -163,6 +167,24 @@ app.use((req, res, next) => { | ||
163 | next(); | 167 | next(); |
164 | }); | 168 | }); |
165 | 169 | ||
170 | +// redis seo | ||
171 | +app.use((req, res, next) => { | ||
172 | + if (!req.xhr) { | ||
173 | + tdk('url', `${req.hostname}${req.originalUrl}`, req).then(TDKObj =>{ | ||
174 | + if (TDKObj[0]) { | ||
175 | + req.tdk = { | ||
176 | + title: TDKObj[1], | ||
177 | + keywords: TDKObj[2], | ||
178 | + description: TDKObj[3] | ||
179 | + }; | ||
180 | + } | ||
181 | + next(); | ||
182 | + }); | ||
183 | + } else { | ||
184 | + return next(); | ||
185 | + } | ||
186 | +}); | ||
187 | + | ||
166 | const logger = global.yoho.logger; | 188 | const logger = global.yoho.logger; |
167 | 189 | ||
168 | // dispatcher | 190 | // dispatcher |
@@ -13,6 +13,7 @@ const headerModel = require('../../../doraemon/models/header'); | @@ -13,6 +13,7 @@ const headerModel = require('../../../doraemon/models/header'); | ||
13 | const ghelper = require('../models/guang-helper'); | 13 | const ghelper = require('../models/guang-helper'); |
14 | const urlHelper = require('../models/url-helper'); | 14 | const urlHelper = require('../models/url-helper'); |
15 | const querystring = require('querystring'); | 15 | const querystring = require('querystring'); |
16 | +const tdk = require('../../../utils/getTDK'); | ||
16 | 17 | ||
17 | /** | 18 | /** |
18 | * 首页文章列表 类型列表 | 19 | * 首页文章列表 类型列表 |
@@ -252,7 +253,8 @@ exports.detail = (req, res, next) => { | @@ -252,7 +253,8 @@ exports.detail = (req, res, next) => { | ||
252 | reqCtx.getArticleBaseInfo(id, uid, udid), | 253 | reqCtx.getArticleBaseInfo(id, uid, udid), |
253 | reqCtx.getArticleRelateBrand(id), | 254 | reqCtx.getArticleRelateBrand(id), |
254 | reqCtx.getRecoArticles(gender, 1, 10, channel), | 255 | reqCtx.getRecoArticles(gender, 1, 10, channel), |
255 | - reqCtx.getAds(channel, isAdDegrade) | 256 | + reqCtx.getAds(channel, isAdDegrade), |
257 | + tdk('article', id, req) | ||
256 | ]; | 258 | ]; |
257 | 259 | ||
258 | if (info.authorId) { | 260 | if (info.authorId) { |
@@ -275,6 +277,24 @@ exports.detail = (req, res, next) => { | @@ -275,6 +277,24 @@ exports.detail = (req, res, next) => { | ||
275 | res.set('Cache-Control', 'no-cache'); | 277 | res.set('Cache-Control', 'no-cache'); |
276 | } | 278 | } |
277 | 279 | ||
280 | + let title, keywords, description; | ||
281 | + | ||
282 | + if (ret[8][0]) { | ||
283 | + req.tdk = { | ||
284 | + title: ret[8][1], | ||
285 | + keywords: ret[8][2], | ||
286 | + description: ret[8][3] | ||
287 | + }; | ||
288 | + } | ||
289 | + | ||
290 | + title = `${info.title} | YOHO!BUY有货`; | ||
291 | + keywords = info.tag.length > 0 ? `${info.tag}` : | ||
292 | + ['Yoho! 有货,潮流,时尚,流行,购物,B2C,正品,购物网站,网上购物,货到付款,品牌服饰,男士护肤,', | ||
293 | + '黑框眼镜,匡威,板鞋,i.t,izzue,5cm,eastpak,vans,lylescott,g-shock,new balance,lacoste,melissa,', | ||
294 | + 'casio,卡西欧手表,舒雅,jasonwood,odm,AAAA,香港购物,日本潮流'].join(''); | ||
295 | + description = info.desc.length > 0 ? `${info.desc}` : | ||
296 | + '潮流商品搜索,上衣,衬衫,TEE,卫衣,冲锋衣,风衣,羽绒服,裤子,休闲鞋,板鞋,配饰,复古眼镜'; | ||
297 | + | ||
278 | res.render('guang/detail', Object.assign({ | 298 | res.render('guang/detail', Object.assign({ |
279 | module: 'guang', | 299 | module: 'guang', |
280 | page: 'detail', | 300 | page: 'detail', |
@@ -305,13 +325,9 @@ exports.detail = (req, res, next) => { | @@ -305,13 +325,9 @@ exports.detail = (req, res, next) => { | ||
305 | commentFirstPageUrl: '?pageSize=10' | 325 | commentFirstPageUrl: '?pageSize=10' |
306 | } | 326 | } |
307 | }, { | 327 | }, { |
308 | - title: `${info.title} | YOHO!BUY有货`, | ||
309 | - keywords: info.tag.length > 0 ? `${info.tag}` : | ||
310 | - ['Yoho! 有货,潮流,时尚,流行,购物,B2C,正品,购物网站,网上购物,货到付款,品牌服饰,男士护肤,', | ||
311 | - '黑框眼镜,匡威,板鞋,i.t,izzue,5cm,eastpak,vans,lylescott,g-shock,new balance,lacoste,melissa,', | ||
312 | - 'casio,卡西欧手表,舒雅,jasonwood,odm,AAAA,香港购物,日本潮流'].join(''), | ||
313 | - description: info.desc.length > 0 ? `${info.desc}` : | ||
314 | - '潮流商品搜索,上衣,衬衫,TEE,卫衣,冲锋衣,风衣,羽绒服,裤子,休闲鞋,板鞋,配饰,复古眼镜', | 328 | + title: title, |
329 | + keywords: keywords, | ||
330 | + description: description, | ||
315 | webNavHeader: channel | 331 | webNavHeader: channel |
316 | })); | 332 | })); |
317 | }); | 333 | }); |
@@ -31,7 +31,7 @@ const showMain = (req, res, next) => { | @@ -31,7 +31,7 @@ const showMain = (req, res, next) => { | ||
31 | saveInCookies: null | 31 | saveInCookies: null |
32 | }; | 32 | }; |
33 | 33 | ||
34 | - return service.showMainAsync(Object.assign({ | 34 | + return service.showMainAsync(req, Object.assign({ |
35 | skn: skn, | 35 | skn: skn, |
36 | channel: channel, | 36 | channel: channel, |
37 | gender: gender | 37 | gender: gender |
@@ -9,6 +9,7 @@ const list = require(`${mRoot}/list`); | @@ -9,6 +9,7 @@ const list = require(`${mRoot}/list`); | ||
9 | const listSeoMap = require(`${global.middleware}/seo/listSeoMap`); | 9 | const listSeoMap = require(`${global.middleware}/seo/listSeoMap`); |
10 | const helpers = global.yoho.helpers; | 10 | const helpers = global.yoho.helpers; |
11 | const _ = require('lodash'); | 11 | const _ = require('lodash'); |
12 | +const tdk = require('../../../utils/getTDK'); | ||
12 | 13 | ||
13 | // 搜索相关接口 | 14 | // 搜索相关接口 |
14 | const searchApi = require(`${mRoot}/search-api`); | 15 | const searchApi = require(`${mRoot}/search-api`); |
@@ -22,7 +23,15 @@ const shop = (shopId, req, res, next, brandInfo) => { | @@ -22,7 +23,15 @@ const shop = (shopId, req, res, next, brandInfo) => { | ||
22 | shopId = parseInt(shopId, 10); | 23 | shopId = parseInt(shopId, 10); |
23 | Object.assign(params, {shopId: shopId}); | 24 | Object.assign(params, {shopId: shopId}); |
24 | 25 | ||
25 | - list.getShopInfo(shopId, req.user.uid).then(shopInfo => { | 26 | + tdk('shop', shopId, req).then(TDKObj => { |
27 | + if (TDKObj[0]) { | ||
28 | + req.tdk = { | ||
29 | + title: TDKObj[1], | ||
30 | + keywords: TDKObj[2], | ||
31 | + description: TDKObj[3] | ||
32 | + }; | ||
33 | + } | ||
34 | + return list.getShopInfo(shopId, req.user.uid).then(shopInfo => { | ||
26 | let pjax = params._pjax; | 35 | let pjax = params._pjax; |
27 | 36 | ||
28 | // 获取不到店铺信息跳转至首页 | 37 | // 获取不到店铺信息跳转至首页 |
@@ -59,6 +68,7 @@ const shop = (shopId, req, res, next, brandInfo) => { | @@ -59,6 +68,7 @@ const shop = (shopId, req, res, next, brandInfo) => { | ||
59 | if (!result.shopTopBanner) { | 68 | if (!result.shopTopBanner) { |
60 | res.set('Cache-Control', 'no-cache'); | 69 | res.set('Cache-Control', 'no-cache'); |
61 | } | 70 | } |
71 | + | ||
62 | res.render('list/shop-index', result); | 72 | res.render('list/shop-index', result); |
63 | }).catch(next); | 73 | }).catch(next); |
64 | } else { // 基础模板 | 74 | } else { // 基础模板 |
@@ -70,10 +80,14 @@ const shop = (shopId, req, res, next, brandInfo) => { | @@ -70,10 +80,14 @@ const shop = (shopId, req, res, next, brandInfo) => { | ||
70 | if (!result.brand || !result.brand.shopBanner) { | 80 | if (!result.brand || !result.brand.shopBanner) { |
71 | res.set('Cache-Control', 'no-cache'); | 81 | res.set('Cache-Control', 'no-cache'); |
72 | } | 82 | } |
83 | + | ||
73 | res.render('list/brand', result); | 84 | res.render('list/brand', result); |
74 | }).catch(next); | 85 | }).catch(next); |
75 | } | 86 | } |
87 | + }); | ||
76 | }).catch(next); | 88 | }).catch(next); |
89 | + | ||
90 | + | ||
77 | }; | 91 | }; |
78 | 92 | ||
79 | /** | 93 | /** |
@@ -35,6 +35,7 @@ const HeaderModel = require('../../../doraemon/models/header'); | @@ -35,6 +35,7 @@ const HeaderModel = require('../../../doraemon/models/header'); | ||
35 | const BLANK_STR = ' '; | 35 | const BLANK_STR = ' '; |
36 | const BUNDLE_PRODUCE = 2; // 量贩 | 36 | const BUNDLE_PRODUCE = 2; // 量贩 |
37 | const BUNDLE_PACKAGE = 1; // 套餐 | 37 | const BUNDLE_PACKAGE = 1; // 套餐 |
38 | +const tdk = require('../../../utils/getTDK'); | ||
38 | 39 | ||
39 | // 展览票 | 40 | // 展览票 |
40 | const YOHOOD_TICKET = 51335912; | 41 | const YOHOOD_TICKET = 51335912; |
@@ -1514,7 +1515,7 @@ const _removeSalePrice = (productInfo) => { | @@ -1514,7 +1515,7 @@ const _removeSalePrice = (productInfo) => { | ||
1514 | /** | 1515 | /** |
1515 | * 获取某一个商品详情主页面 | 1516 | * 获取某一个商品详情主页面 |
1516 | */ | 1517 | */ |
1517 | -const showMainAsync = (data) => { | 1518 | +const showMainAsync = (req, data) => { |
1518 | return co(function * () { | 1519 | return co(function * () { |
1519 | // 获取商品基本信息 | 1520 | // 获取商品基本信息 |
1520 | let productData = yield productAPI.getProductAsync({skn: data.skn}, data.uid, data.isStudent, data.vipLevel); | 1521 | let productData = yield productAPI.getProductAsync({skn: data.skn}, data.uid, data.isStudent, data.vipLevel); |
@@ -1537,7 +1538,8 @@ const showMainAsync = (data) => { | @@ -1537,7 +1538,8 @@ const showMainAsync = (data) => { | ||
1537 | _getSortNavAsync(smallSortId, data.gender), // 面包屑导航 | 1538 | _getSortNavAsync(smallSortId, data.gender), // 面包屑导航 |
1538 | HeaderModel.requestHeaderData(data.channel), // 通用头部数据 | 1539 | HeaderModel.requestHeaderData(data.channel), // 通用头部数据 |
1539 | _getProductIntroAsync(productId, productSkn), // 商品详细介绍 | 1540 | _getProductIntroAsync(productId, productSkn), // 商品详细介绍 |
1540 | - curUserProduct(productData) // 商品详细价格 | 1541 | + curUserProduct(productData), // 商品详细价格 |
1542 | + tdk('skn', data.skn, req) // seo | ||
1541 | ]); | 1543 | ]); |
1542 | 1544 | ||
1543 | let smallSortNavigator = requestData[0]; | 1545 | let smallSortNavigator = requestData[0]; |
@@ -1545,6 +1547,14 @@ const showMainAsync = (data) => { | @@ -1545,6 +1547,14 @@ const showMainAsync = (data) => { | ||
1545 | let productDescription = requestData[2]; | 1547 | let productDescription = requestData[2]; |
1546 | let productInfo = requestData[3]; | 1548 | let productInfo = requestData[3]; |
1547 | 1549 | ||
1550 | + if (requestData[4][0]) { | ||
1551 | + req.tdk = { | ||
1552 | + title: requestData[4][1], | ||
1553 | + keywords: requestData[4][2], | ||
1554 | + description: requestData[4][3] | ||
1555 | + }; | ||
1556 | + } | ||
1557 | + | ||
1548 | // 拼装数据 | 1558 | // 拼装数据 |
1549 | let result = {}; | 1559 | let result = {}; |
1550 | 1560 |
@@ -17,18 +17,18 @@ module.exports = { | @@ -17,18 +17,18 @@ module.exports = { | ||
17 | cookieDomain: '.yohobuy.com', | 17 | cookieDomain: '.yohobuy.com', |
18 | domains: { | 18 | domains: { |
19 | // test3 | 19 | // test3 |
20 | - singleApi: 'http://api-test3.yohops.com:9999/', | ||
21 | - api: 'http://api-test3.yohops.com:9999/', | ||
22 | - service: 'http://service-test3.yohops.com:9999/', | ||
23 | - serviceNotify: 'http://service-test3.yohops.com:9999/', | ||
24 | - global: 'http://global-test-soa.yohops.com:9999/', | 20 | + // singleApi: 'http://api-test3.yohops.com:9999/', |
21 | + // api: 'http://api-test3.yohops.com:9999/', | ||
22 | + // service: 'http://service-test3.yohops.com:9999/', | ||
23 | + // serviceNotify: 'http://service-test3.yohops.com:9999/', | ||
24 | + // global: 'http://global-test-soa.yohops.com:9999/', | ||
25 | 25 | ||
26 | // prod | 26 | // prod |
27 | - // singleApi: 'http://single.yoho.cn/', | ||
28 | - // api: 'http://api.yoho.cn/', | ||
29 | - // service: 'http://service.yoho.cn/', | ||
30 | - // serviceNotify: 'http://service.yoho.cn/', | ||
31 | - // global: 'http://api-global.yohobuy.com/', | 27 | + singleApi: 'http://single.yoho.cn/', |
28 | + api: 'http://api.yoho.cn/', | ||
29 | + service: 'http://service.yoho.cn/', | ||
30 | + serviceNotify: 'http://service.yoho.cn/', | ||
31 | + global: 'http://api-global.yohobuy.com/', | ||
32 | 32 | ||
33 | // gray | 33 | // gray |
34 | // singleApi: 'http://single.gray.yohops.com/', | 34 | // singleApi: 'http://single.gray.yohops.com/', |
@@ -131,7 +131,26 @@ module.exports = { | @@ -131,7 +131,26 @@ module.exports = { | ||
131 | }, | 131 | }, |
132 | zookeeperServer: '192.168.102.168:2188', | 132 | zookeeperServer: '192.168.102.168:2188', |
133 | maxQps: 1200, | 133 | maxQps: 1200, |
134 | - sessionMemcachedPrefix: 'yohobuy_session:' | 134 | + sessionMemcachedPrefix: 'yohobuy_session:', |
135 | + redis: { | ||
136 | + connect: { | ||
137 | + host: '127.0.0.1', | ||
138 | + port: '6379', | ||
139 | + retry_strategy(options) { | ||
140 | + if (options.error && options.error.code === 'ECONNREFUSED') { | ||
141 | + console.log('redis连接不成功'); | ||
142 | + } | ||
143 | + if (options.total_retry_time > 1000 * 60 * 60 * 6) { | ||
144 | + console.log('redis连接超时'); | ||
145 | + return; | ||
146 | + } | ||
147 | + if (options.attempt > 10) { | ||
148 | + return 1000 * 60 * 60 * 0.5; | ||
149 | + } | ||
150 | + return Math.min(options.attempt * 100, 1000); | ||
151 | + } | ||
152 | + } | ||
153 | + } | ||
135 | }; | 154 | }; |
136 | 155 | ||
137 | if (isProduction) { | 156 | if (isProduction) { |
@@ -165,7 +184,26 @@ if (isProduction) { | @@ -165,7 +184,26 @@ if (isProduction) { | ||
165 | open: false, | 184 | open: false, |
166 | url: 'http://123.206.2.55/strategy' | 185 | url: 'http://123.206.2.55/strategy' |
167 | }, | 186 | }, |
168 | - zookeeperServer: 'web.zookeeper.yohoops.org:2181' | 187 | + zookeeperServer: 'web.zookeeper.yohoops.org:2181', |
188 | + redis: { | ||
189 | + connect: { | ||
190 | + host: 'web.redis.yohoops.org' | ||
191 | + }, | ||
192 | + port: '6379', | ||
193 | + retry_strategy(options) { | ||
194 | + if (options.error && options.error.code === 'ECONNREFUSED') { | ||
195 | + console.log('redis连接不成功'); | ||
196 | + } | ||
197 | + if (options.total_retry_time > 1000 * 60 * 60 * 6) { | ||
198 | + console.log('redis连接超时'); | ||
199 | + return; | ||
200 | + } | ||
201 | + if (options.attempt > 10) { | ||
202 | + return 1000 * 60 * 60 * 0.5; | ||
203 | + } | ||
204 | + return Math.min(options.attempt * 100, 1000); | ||
205 | + } | ||
206 | + } | ||
169 | }); | 207 | }); |
170 | } else if (isTest) { | 208 | } else if (isTest) { |
171 | Object.assign(module.exports, { | 209 | Object.assign(module.exports, { |
@@ -74,7 +74,6 @@ module.exports = [ | @@ -74,7 +74,6 @@ module.exports = [ | ||
74 | { | 74 | { |
75 | type: TYPE.rewrite, | 75 | type: TYPE.rewrite, |
76 | origin: (req) => { | 76 | origin: (req) => { |
77 | - console.log(req.path); | ||
78 | return req.path === '/erp2goods'; | 77 | return req.path === '/erp2goods'; |
79 | }, | 78 | }, |
80 | target: '/common/erp2goods' | 79 | target: '/common/erp2goods' |
doraemon/middleware/redis.js
0 → 100644
1 | +const redis = require('redis'); | ||
2 | +const bluebird = require('bluebird'); | ||
3 | +const config = require('../../config/common'); | ||
4 | +let client; | ||
5 | + | ||
6 | +try { | ||
7 | + client = redis.createClient(config.redis.connect); | ||
8 | + | ||
9 | + bluebird.promisifyAll(redis.RedisClient.prototype); | ||
10 | + bluebird.promisifyAll(redis.Multi.prototype); | ||
11 | + | ||
12 | + client.on('error', function() { | ||
13 | + global.yoho.redis = ''; | ||
14 | + }); | ||
15 | + | ||
16 | + client.on('connect', function() { | ||
17 | + global.yoho.redis = client; | ||
18 | + }); | ||
19 | +} catch (e) { | ||
20 | + global.yoho.redis = ''; | ||
21 | +} | ||
22 | + | ||
23 | + | ||
24 | + | ||
25 | +module.exports = client; |
@@ -44,15 +44,15 @@ | @@ -44,15 +44,15 @@ | ||
44 | "passport-sina": "^0.1.0", | 44 | "passport-sina": "^0.1.0", |
45 | "passport-strategy": "1.x.x", | 45 | "passport-strategy": "1.x.x", |
46 | "passport-weixin": "^0.1.0", | 46 | "passport-weixin": "^0.1.0", |
47 | + "redis": "^2.7.1", | ||
47 | "request": "^2.81.0", | 48 | "request": "^2.81.0", |
48 | "request-ip": "^1.2.2", | 49 | "request-ip": "^1.2.2", |
49 | "request-promise": "^3.0.0", | 50 | "request-promise": "^3.0.0", |
50 | "serve-favicon": "^2.3.0", | 51 | "serve-favicon": "^2.3.0", |
51 | - "sitemap": "^1.12.0", | ||
52 | "urlencode": "^1.1.0", | 52 | "urlencode": "^1.1.0", |
53 | "uuid": "^2.0.2", | 53 | "uuid": "^2.0.2", |
54 | "yoho-express-session": "^2.0.0", | 54 | "yoho-express-session": "^2.0.0", |
55 | - "yoho-node-lib": "^0.2.23", | 55 | + "yoho-node-lib": "^0.2.28", |
56 | "yoho-zookeeper": "^1.0.8" | 56 | "yoho-zookeeper": "^1.0.8" |
57 | }, | 57 | }, |
58 | "devDependencies": { | 58 | "devDependencies": { |
utils/getTDK.js
0 → 100644
1 | +const md5 = require('md5'); | ||
2 | +const redis = global.yoho.redis; | ||
3 | +const _ = require('lodash'); | ||
4 | + | ||
5 | +module.exports = (type, query, req) => { | ||
6 | + query = type === 'url' ? md5(query) : query; | ||
7 | + | ||
8 | + if (redis && _.get(req.app.locals.pc, 'ci.tdk', false)) { | ||
9 | + let arr = []; | ||
10 | + | ||
11 | + arr.push(redis.multi([ | ||
12 | + ['exists', `tdk:${type}:${query}`], | ||
13 | + ['hmget', `tdk:${type}:${query}`, 'key', 'title', 'keywords', 'description'] | ||
14 | + ]).execAsync()); | ||
15 | + | ||
16 | + arr.push(new Promise((resolve)=>{ | ||
17 | + setTimeout(resolve, 500, []); | ||
18 | + })); | ||
19 | + | ||
20 | + return Promise.race(arr).then(function(res) { | ||
21 | + if (res.length) { | ||
22 | + return res[1]; | ||
23 | + } else { | ||
24 | + return []; | ||
25 | + } | ||
26 | + }); | ||
27 | + } else { | ||
28 | + return Promise.resolve([]); | ||
29 | + } | ||
30 | + | ||
31 | +}; |
-
Please register or login to post a comment