diff --git a/.eslintrc b/.eslintrc
index 5a39e4a..1d43459 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -10,4 +10,4 @@
         "camelcase": "off"
     }
 
-}
+}
\ No newline at end of file
diff --git a/app.js b/app.js
index 49b338d..86ef08e 100644
--- a/app.js
+++ b/app.js
@@ -43,6 +43,9 @@ yohoLib.global(config);
 
 const logger = global.yoho.logger;
 
+// tdk
+global.yoho.redis = require('./doraemon/middleware/redis');
+
 // zookeeper
 if (config.zookeeperServer) {
     require('yoho-zookeeper')(config.zookeeperServer, 'wap', app.locals.wap = {}, global.yoho.cache);
@@ -176,8 +179,11 @@ app.use((req, res, next) => {
 // 添加请求上下文
 app.use(global.yoho.httpCtx());
 
+// redis seo
+
 // dispatcher
 try {
+    const tdkUrl = require('./doraemon/middleware/redis-url');
     const user = require('./doraemon/middleware/user');
     const reqParamsFilter = require('./doraemon/middleware/req-params-filter');
     const urlRewrite = require('./doraemon/middleware/url-rewrite');
@@ -192,6 +198,7 @@ try {
     const pageCache = require('./doraemon/middleware/page-cache');
 
     // YOHO 前置中间件
+    app.use(tdkUrl());
     app.use(reqParamsFilter());
     app.use(urlRewrite());
     app.use(subDomain());
diff --git a/apps/guang/controllers/detail.js b/apps/guang/controllers/detail.js
index fe1d1be..019fb5c 100644
--- a/apps/guang/controllers/detail.js
+++ b/apps/guang/controllers/detail.js
@@ -14,6 +14,7 @@ const stringProcess = require(`${global.utils}/string-process`);
 const guangProcess = require(`${global.utils}/guang-process`);
 const headerModel = require('../../../doraemon/models/header'); // 头部model
 const aboutModel = require('../../../doraemon/models/about');
+const tdk = require('../../../utils/getTDK');
 const qs = require('querystring');
 const channels = {
     boys: 1,
@@ -167,6 +168,15 @@ const index = (req, res, next) => {
     isShare = isWeixin || isqq || isWeibo ? true : false;
 
     co(function* () {
+        let ret = yield tdk('article', id, req);
+
+        if (ret[0]) {
+            req.tdk = {
+                title: ret[1],
+                keywords: ret[2],
+                description: ret[3]
+            };
+        }
         let detail = yield req.ctx(DetailModel).packageData(id, isApp, isWeixin, channel, isShare);
         let commentsTotal = yield req.ctx(DetailModel).commentsTotal({article_id: id, udid: udid});
         let praise = yield req.ctx(DetailModel).getArticlePraiseAndFavor({
diff --git a/apps/product/controllers/new-detail.js b/apps/product/controllers/new-detail.js
index 44e1a66..4d99eee 100644
--- a/apps/product/controllers/new-detail.js
+++ b/apps/product/controllers/new-detail.js
@@ -9,6 +9,7 @@ const newDetailModel = require('../models/new-detail');
 const listModel = require('../models/list');
 const headerModel = require('../../../doraemon/models/header'); // 头部model
 const qs = require('querystring');
+const tdk = require('../../../utils/getTDK');
 const helpers = global.yoho.helpers;
 
 const newDetail = {
@@ -32,11 +33,21 @@ const newDetail = {
             navTitle: '商品详情'
         });
 
-        newDetailModel.getProductData({
-            id: id,
-            goodsId: goodsId,
-            productSkn: productSkn,
-            ua: req.get('user-agent') || ''
+        tdk('skn', productSkn, req).then(ret => {
+            if (ret[0]) {
+                req.tdk = {
+                    title: ret[1],
+                    keywords: ret[2],
+                    description: ret[3]
+                };
+            }
+
+            return newDetailModel.getProductData({
+                id: id,
+                goodsId: goodsId,
+                productSkn: productSkn,
+                ua: req.get('user-agent') || ''
+            });
         }).then((result) => {
             if (_.isEmpty(result)) {
                 return next();
diff --git a/apps/product/controllers/new-shop.js b/apps/product/controllers/new-shop.js
index 862c4fe..741c32e 100644
--- a/apps/product/controllers/new-shop.js
+++ b/apps/product/controllers/new-shop.js
@@ -15,6 +15,7 @@ const helpers = global.yoho.helpers;
 const productProcess = require(`${utils}/product-process`);
 const redShopPrcs = require(`${utils}/redshop-process`);
 const co = require('bluebird').coroutine;
+const tdk = require('../../../utils/getTDK');
 
 /**
  * 从 useragent 获取 uid
@@ -61,101 +62,114 @@ const shop = {
 
             brandLogo = result;
 
-            title = brandLogo.name;
+            return co(function*() {
+                title = brandLogo.name;
 
-            if (brandLogo && brandLogo.id) {
-                brandId = brandLogo.id;
-            }
+                if (brandLogo && brandLogo.id) {
+                    brandId = brandLogo.id;
+                }
+                if (brandLogo && brandLogo.shopId) {
+                    let TDKObj = yield tdk('shop', brandLogo.shopId, req);
+
+                    if (TDKObj[0]) {
+                        req.tdk = {
+                            title: TDKObj[1],
+                            keywords: TDKObj[2],
+                            description: TDKObj[3]
+                        };
+                    }
+                }
 
-            params.brand = brandId;
+                params.brand = brandId;
 
-            // 唤起 APP 的路径
-            res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.brand","params":{"brand_id":"${brandId}"}}`;
+                // 唤起 APP 的路径
+                res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.brand","params":{"brand_id":"${brandId}"}}`;
 
-            let searchParam = Object.assign({
-                isApp: req.yoho.isApp,
-                brand: brandId,
-                type: 'default',
-                order: '0',
-                page: 1,
-                limit: 4,
-            }, params);
+                let searchParam = Object.assign({
+                    isApp: req.yoho.isApp,
+                    brand: brandId,
+                    type: 'default',
+                    order: '0',
+                    page: 1,
+                    limit: 4,
+                }, params);
 
-            if (uid) {
-                searchParam.uid = uid;
-            }
+                if (uid) {
+                    searchParam.uid = uid;
+                }
 
-            if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
-                req.query.shop_id = brandLogo.shopId;
-                shop.shop(req, res, next);
-                return false;
-            } else if (req.query.from === 'search') {
-                return Promise.all([
-                    listModel.getBrandShops(brandLogo.brandDomain, req),
-                    searchModel.getSearchData(searchParam)
-                ]).then(shopResult => {
-                    let brandShop = shopResult[0];
-                    let newGoods = shopResult[1];
-
-                    params.newGoods = newGoods.list || [];
-                    params.suggestion = newGoods.suggestion || [];
-
-                    // 推荐词条件判断 redmine: 18567
-                    if (params.suggestion && params.suggestion.isNeedSuggestion &&
-                        params.suggestion.termsSuggestion.length) {
-                        params.newquery = params.suggestion.termsSuggestion[0].name;
-                    }
+                if (req.query.from !== 'search' && brandLogo.type === '2' && brandLogo.shopId) {
+                    req.query.shop_id = brandLogo.shopId;
+                    shop.shop(req, res, next);
+                    return false;
+                } else if (req.query.from === 'search') {
+                    return Promise.all([
+                        listModel.getBrandShops(brandLogo.brandDomain, req),
+                        searchModel.getSearchData(searchParam)
+                    ]).then(shopResult => {
+                        let brandShop = shopResult[0];
+                        let newGoods = shopResult[1];
 
-                    if (brandId === 0) {
-                        params.query = domain;
-                    }
+                        params.newGoods = newGoods.list || [];
+                        params.suggestion = newGoods.suggestion || [];
 
-                    if (req.query.app_type && parseInt(req.query.app_type, 10) === 1) {
-                        shopEnter = false;
-                    } else {
-                        shopEnter = true;
-                    }
+                        // 推荐词条件判断 redmine: 18567
+                        if (params.suggestion && params.suggestion.isNeedSuggestion &&
+                            params.suggestion.termsSuggestion.length) {
+                            params.newquery = params.suggestion.termsSuggestion[0].name;
+                        }
+
+                        if (brandId === 0) {
+                            params.query = domain;
+                        }
 
-                    if (brandShop.length > 0 || brandLogo && shopEnter) {
+                        if (req.query.app_type && parseInt(req.query.app_type, 10) === 1) {
+                            shopEnter = false;
+                        } else {
+                            shopEnter = true;
+                        }
 
-                        params = _.assign({
-                            brandWay: _.isEmpty(brandShop) ? brandLogo : brandShop,
-                            search: {
-                                default: req.query.query || req.query.domain,
-                                url: helpers.urlFormat('', null, 'search')
-                            }
-                        }, params);
-                    }
+                        if (brandShop.length > 0 || brandLogo && shopEnter) {
 
-                    return true;
-                });
-            } else {
-                params.brandHome = {
-                    title: result.name,
-                    id: result.id
-                };
-                return Promise.all([
-                    listModel.getBrandBanner(brandId),
-                    searchModel.getSearchData(searchParam)
-                ]).then(brandResult => {
-                    let brandBanner = brandResult[0];
-                    let newGoods = brandResult[1];
-
-                    if (!brandBanner || !newGoods) {
-                        res.set('Cache-Control', 'no-cache');
-                    }
+                            params = _.assign({
+                                brandWay: _.isEmpty(brandShop) ? brandLogo : brandShop,
+                                search: {
+                                    default: req.query.query || req.query.domain,
+                                    url: helpers.urlFormat('', null, 'search')
+                                }
+                            }, params);
+                        }
 
-                    // 品牌没有 Banner 整个头部不显示
-                    if (!brandBanner) {
-                        params.brandHome = null;
-                    } else {
-                        params.brandHome.banner = brandBanner;
-                    }
+                        return true;
+                    });
+                } else {
+                    params.brandHome = {
+                        title: result.name,
+                        id: result.id
+                    };
+                    return Promise.all([
+                        listModel.getBrandBanner(brandId),
+                        searchModel.getSearchData(searchParam)
+                    ]).then(brandResult => {
+                        let brandBanner = brandResult[0];
+                        let newGoods = brandResult[1];
 
-                    params.newGoods = newGoods.list;
-                    return true;
-                });
-            }
+                        if (!brandBanner || !newGoods) {
+                            res.set('Cache-Control', 'no-cache');
+                        }
+
+                        // 品牌没有 Banner 整个头部不显示
+                        if (!brandBanner) {
+                            params.brandHome = null;
+                        } else {
+                            params.brandHome.banner = brandBanner;
+                        }
+
+                        params.newGoods = newGoods.list;
+                        return true;
+                    });
+                }
+            })();
         }).then((isBrand) => {
             if (isBrand) {
                 params.isBrand = isBrand;
diff --git a/apps/product/controllers/seckill-detail.js b/apps/product/controllers/seckill-detail.js
index 384900d..0355db9 100644
--- a/apps/product/controllers/seckill-detail.js
+++ b/apps/product/controllers/seckill-detail.js
@@ -9,6 +9,7 @@ const seckillDetailModel = require('../models/seckill-detail');
 const newDetailModel = require('../models/new-detail');
 const listModel = require('../models/list');
 const headerModel = require('../../../doraemon/models/header'); // 头部model
+const tdk = require('../../../utils/getTDK');
 const helpers = global.yoho.helpers;
 
 const newDetail = {
@@ -30,11 +31,20 @@ const newDetail = {
             navTitle: '商品详情'
         });
 
-        newDetailModel.getProductData({
-            id: id,
-            goodsId: goodsId,
-            productSkn: productSkn,
-            ua: req.get('user-agent') || ''
+        tdk('skn', productSkn, req).then(ret => {
+            if (ret[0]) {
+                req.tdk = {
+                    title: ret[1],
+                    keywords: ret[2],
+                    description: ret[3]
+                };
+            }
+            return newDetailModel.getProductData({
+                id: id,
+                goodsId: goodsId,
+                productSkn: productSkn,
+                ua: req.get('user-agent') || ''
+            });
         }).then((result) => {
             if (_.isEmpty(result)) {
                 return next();
diff --git a/config/common.js b/config/common.js
index 5415028..4952d56 100644
--- a/config/common.js
+++ b/config/common.js
@@ -100,7 +100,26 @@ module.exports = {
     },
     maxQps: 1200,
     geetestJs: '//static.geetest.com/static/tools/gt.js',
-    jsSdk: '//cdn.yoho.cn/js-sdk/1.2.2/jssdk.js'
+    jsSdk: '//cdn.yoho.cn/js-sdk/1.2.2/jssdk.js',
+    redis: {
+        connect: {
+            host: '127.0.0.1',
+            port: '6379',
+            retry_strategy(options) {
+                if (options.error && options.error.code === 'ECONNREFUSED') {
+                    console.log('redis连接不成功');
+                }
+                if (options.total_retry_time > 1000 * 60 * 60 * 6) {
+                    console.log('redis连接超时');
+                    return;
+                }
+                if (options.attempt > 10) {
+                    return 1000 * 60 * 60 * 0.5;
+                }
+                return Math.min(options.attempt * 100, 1000);
+            }
+        }
+    }
 };
 
 if (isProduction) {
@@ -152,6 +171,25 @@ if (isProduction) {
             key: '7e6f3307b64cc87c79c472814b88f7fb',
             appSecret: 'ce21ae4a3f93852279175a167e54509b',
             notifyUrl: 'http://service.yoho.cn/payment/weixin_notify',
+        },
+        redis: {
+            connect: {
+                host: 'web.redis.yohoops.org'
+            },
+            port: '6379',
+            retry_strategy(options) {
+                if (options.error && options.error.code === 'ECONNREFUSED') {
+                    console.log('redis连接不成功');
+                }
+                if (options.total_retry_time > 1000 * 60 * 60 * 6) {
+                    console.log('redis连接超时');
+                    return;
+                }
+                if (options.attempt > 10) {
+                    return 1000 * 60 * 60 * 0.5;
+                }
+                return Math.min(options.attempt * 100, 1000);
+            }
         }
     });
 } else if (isTest) {
diff --git a/doraemon/middleware/redis-url.js b/doraemon/middleware/redis-url.js
new file mode 100644
index 0000000..ff67f50
--- /dev/null
+++ b/doraemon/middleware/redis-url.js
@@ -0,0 +1,21 @@
+'use strict';
+const tdk = require('../../utils/getTDK');
+
+module.exports = () => {
+    return (req, res, next) => {
+        if (!req.xhr) {
+            tdk('url', `${req.hostname}${req.originalUrl}`, req).then(TDKObj =>{
+                if (TDKObj[0]) {
+                    req.tdk = {
+                        title: TDKObj[1],
+                        keywords: TDKObj[2],
+                        description: TDKObj[3]
+                    };
+                }
+                next();
+            });
+        } else {
+            return next();
+        }
+    };
+};
diff --git a/doraemon/middleware/redis.js b/doraemon/middleware/redis.js
new file mode 100644
index 0000000..ffd5879
--- /dev/null
+++ b/doraemon/middleware/redis.js
@@ -0,0 +1,25 @@
+const redis = require('redis');
+const bluebird = require('bluebird');
+const config = require('../../config/common');
+let client;
+
+try {
+    client = redis.createClient(config.redis.connect);
+
+    bluebird.promisifyAll(redis.RedisClient.prototype);
+    bluebird.promisifyAll(redis.Multi.prototype);
+
+    client.on('error', function() {
+        global.yoho.redis = '';
+    });
+
+    client.on('connect', function() {
+        global.yoho.redis = client;
+    });
+} catch (e) {
+    global.yoho.redis = '';
+}
+
+
+
+module.exports = client;
diff --git a/package.json b/package.json
index 53bb08f..953838e 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
     "passport-sina": "^0.1.0",
     "passport-strategy": "^1.0.0",
     "passport-weixin": "^0.1.0",
+    "redis": "^2.7.1",
     "postcss-calc": "^5.3.1",
     "request": "^2.81.0",
     "request-promise": "^4.2.1",
@@ -55,7 +56,7 @@
     "xml2js": "^0.4.17",
     "yoho-express-session": "^2.0.0",
     "yoho-md5": "^2.0.0",
-    "yoho-node-lib": "=0.2.27",
+    "yoho-node-lib": "=0.2.28",
     "yoho-zookeeper": "^1.0.8"
   },
   "devDependencies": {
diff --git a/utils/getTDK.js b/utils/getTDK.js
new file mode 100644
index 0000000..27174b0
--- /dev/null
+++ b/utils/getTDK.js
@@ -0,0 +1,31 @@
+const md5 = require('md5');
+const redis = global.yoho.redis;
+const _ = require('lodash');
+
+module.exports = (type, query, req) => {
+    query = type === 'url' ? md5(query) : query;
+
+    if (redis && _.get(req.app.locals.pc, 'ci.tdk', false)) {
+        let arr = [];
+
+        arr.push(redis.multi([
+            ['exists', `tdk:${type}:${query}`],
+            ['hmget', `tdk:${type}:${query}`, 'key', 'title', 'keywords', 'description']
+        ]).execAsync());
+
+        arr.push(new Promise((resolve)=>{
+            setTimeout(resolve, 500, []);
+        }));
+
+        return Promise.race(arr).then(function(res) {
+            if (res.length) {
+                return res[1];
+            } else {
+                return [];
+            }
+        });
+    } else {
+        return Promise.resolve([]);
+    }
+
+};