最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解基于Node.js的微信JS-SDK后端接口實現(xiàn)代碼

 更新時間:2017年07月15日 08:52:58   作者:Yuchang_Wu  
本篇文章主要介紹了詳解基于Node.js的微信JS-SDK后端接口實現(xiàn)代碼,具有一定的參考價值,有興趣的可以了解一下

做了一個網(wǎng)站,放到線上,用微信打開,點擊分享,可是分享后發(fā)給朋友的鏈接卡片是微信默認(rèn)自帶的,如下:

 這標(biāo)題,描述以及圖片是默認(rèn)自帶的,丑不說,分享給別人還以為是盜號網(wǎng)站呢,而接入微信的JSSDK后,分享可以自定義內(nèi)容,如下:

 我承認(rèn),雖然這分享的標(biāo)題和內(nèi)容也并不正經(jīng),但這不妨礙我表達(dá)我們可以通過微信JSSDK定義分享內(nèi)容,接下來我們將一步一步從零實現(xiàn)JSSDK從后端Node.js的接入。

成為測試公眾號開發(fā)者

登錄測試公眾號后臺

首先我們需要在微信公眾平臺申請測試接口,地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
使用微信掃描登錄后,即可來微信公眾平臺測試賬號系統(tǒng)。

成為測試公眾號開發(fā)者

其次在微信公眾平臺測試賬號中,掃描測試號二維碼,成為測試公眾號的開發(fā)者

接口配置信息

修改接口配置信息

1.URL地址必須是你服務(wù)器上的地址,此地址要能通過瀏覽器的地址欄訪問到(沒有服務(wù)器?沒關(guān)系,一會兒我們搭建一個)
 假設(shè)我這里填寫的服務(wù)器地址是"http://www.your_server_name.com/wxJssdk"

2.Token你可以隨意填寫,用作生成簽名,(不知道簽名?沒關(guān)系,一會兒會用到這東西的)
 假設(shè)我這里填寫的Token是"jegfjaeghfuccawegfgjdbh"

此時點擊提交是會提示配置失敗的,因為在提交的時候,微信是會請求你的服務(wù)器地址,而你的當(dāng)前配置的地址并不能訪問,所以會提示配置失敗。不過別急,我們先來搭建一個簡單的Node服務(wù)器,讓微信能夠訪問該服務(wù)器。

搭建簡單的Node服務(wù)器

我們需要在http://www.your_server_name.com 這個域名上搭建一個服務(wù)器,并且曝出一個接口為/wxJssdk

const express = require('express')
const app = express()

app.get('/wxJssdk', (req, res) => {
 res.send('請求成功了了了了')
})

app.listen(80, err => {
 if(!err) console.log('connect succeed')
})

現(xiàn)在我們在地址欄中訪問http://www.your_server_name.com/wxJssdk ,如果頁面顯示“請求成功了了了了”,則進(jìn)入到下一步,如果沒有成功的話,檢查一下你的服務(wù)器是否開啟Node服務(wù)器,如:node index.js

此時保存微信測試公眾號后臺的接口配置信息,仍然會提示配置失敗,這是因為我們沒有按照它的要求返回。

根據(jù)微信測試公眾號請求信息返回對應(yīng)內(nèi)容

根據(jù)微信公眾號開發(fā)文檔接入指南,微信在請求我們配置的接口時,會帶上如下信息

參數(shù) 描述
signature 微信加密簽名,signature結(jié)合了開發(fā)者填寫的token參數(shù)和請求中的timestamp參數(shù)、nonce參數(shù)。
timestamp 時間戳
nonce 隨機數(shù)
echostr 隨機字符串

微信服務(wù)器會通過GET請求,來請求我們所配置的接口,并帶上以上表格的信息,而我們必須按照以下要求,將微信發(fā)送的信息進(jìn)行要求校驗,以確保是微信發(fā)送的信息,其中校驗流程如下:

1)將token、timestamp、nonce三個參數(shù)進(jìn)行字典序排序
2)將三個參數(shù)字符串拼接成一個字符串進(jìn)行sha1加密
3)開發(fā)者獲得加密后的字符串可與signature對比,標(biāo)識該請求來源于微信

const express = require('express')
const app = express()
const sha1 = require('sha1')

app.get('/wxJssdk', (req, res) => {
 let wx = req.query

 let token = 'jegfjaeghfuccawegfgjdbh'
 let timestamp = wx.timestamp
 let nonce = wx.nonce

 // 1)將token、timestamp、nonce三個參數(shù)進(jìn)行字典序排序
 let list = [token, timestamp, nonce].sort()

 // 2)將三個參數(shù)字符串拼接成一個字符串進(jìn)行sha1加密
 let str = list.join('')
 let result = sha1(str)

 // 3)開發(fā)者獲得加密后的字符串可與signature對比,標(biāo)識該請求來源于微信
 if (result === wx.signature) {
  res.send(wx.echostr) // 返回微信傳來的echostr,表示校驗成功,此處不能返回其它
 } else {
  res.send(false)
 }
})

此時我們重啟Node服務(wù)器,再次保存接口配置信息即可配置成功。

微信JSSDK使用步驟

根據(jù)微信JSSDK說明文檔,我們需要完成如下:

填寫安全域名

登錄微信公眾平臺進(jìn)入“公眾號設(shè)置”的“功能設(shè)置”里填寫“JS接口安全域名”,即要調(diào)用接口的域名,不包含協(xié)議

前端引入JS

在需要調(diào)用JS接口的頁面引入此JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

填寫接口的配置信息

wx.config({
 debug: true, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會通過log打出,僅在pc端時才會打印。
 appId: '', // 必填,公眾號的唯一標(biāo)識
 timestamp: , // 必填,生成簽名的時間戳
 nonceStr: '', // 必填,生成簽名的隨機串
 signature: '',// 必填,簽名
 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
});

調(diào)用接口

做你前端該做的,調(diào)用微信分享接口,或微信提供的其它接口,whatever you need,當(dāng)然,這并不是我們所要講的重點,我們接下來要看一下微信的配置信息從哪獲取

在Node服務(wù)器中生成jssdk所需要的配置信息

從上一節(jié)可以看到,調(diào)用微信JSSDK需要以下信息

1.appId
2.timestamp
3.nonceStr
4.signature
5.jsApiList

其中:

1.第1項appId是測試公眾號后臺的appId,我們已知
2.第2項時間戳我們也可以自己生成
3.第3項nonceStr可以隨意填寫,你可以理解為密鑰
4.第4項signature則需要我們按要求生成
5.第5項是所需要接口的接口名

生成signature

生成簽名之前必須先了解一下jsapi_ticket,jsapi_ticket是公眾號用于調(diào)用微信JS接口的臨時票據(jù)。正常情況下,jsapi_ticket的有效期為7200秒,通過access_token來獲取。由于獲取jsapi_ticket的api調(diào)用次數(shù)非常有限,頻繁刷新jsapi_ticket會導(dǎo)致api調(diào)用受限,影響自身業(yè)務(wù),開發(fā)者必須在自己的服務(wù)全局緩存jsapi_ticket 。

為了保證我們appid,appsecret,nonceStr等信息不在前端曝露,我們以下步驟將在服務(wù)器上進(jìn)行操作,以免他人盜用信息獲?。ㄗⅲ何⑿耪埱笥忻咳沾螖?shù)限制,一旦超出,則無法使用,具體請求次數(shù)限制在微信公眾號后臺中可查看)

生成access_token

根據(jù)微信開發(fā)文檔[獲取access_token文檔說明],我們需要將微信測試公眾號后臺的appid和和appsecret以GET的請求方式向https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 發(fā)起請求獲取token,請求成功后我們會獲得下返回JSON轉(zhuǎn)化的字符串

{"access_token":"ACCESS_TOKEN","expires_in":7200}

具體請求代碼如下:

const request = require('request')

const grant_type = 'client_credential'
const appid = 'your app id'
const secret = 'your app secret'

request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {
 let access_toekn = JSON.parse(body).access_token
})

獲取jsapi_ticket

const request = require('request')

const grant_type = 'client_credential'
const appid = 'your app id'
const secret = 'your app secret'

request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {
 let access_toekn = JSON.parse(body).access_token

 request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => {
   let jsapi_ticket = JSON.parse(body).ticket
 })
})

生成簽名

生成簽名的步驟和最開始的/wxJssdk的算法是一致的,具體如下:

let jsapi_ticket = jsapi_ticket // 上一步從獲取的jsapi_ticket
let nonce_str = '123456'  // 密鑰,字符串任意,可以隨機生成
let timestamp = new Date().getTime() // 時間戳
let url = req.query.url  // 使用接口的url鏈接,不包含#后的內(nèi)容

// 將請求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此處直接手動排序
let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '&timestamp=' + timestamp + '&url=' + url

// 用sha1加密
let signature = sha1(str)

連接后的代碼為:

const request = require('request')

const grant_type = 'client_credential'
const appid = 'your app id'
const secret = 'your app secret'

request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {
 let access_toekn = JSON.parse(body).access_token

 request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => {
   let jsapi_ticket = JSON.parse(body).ticket
   let nonce_str = '123456'  // 密鑰,字符串任意,可以隨機生成
   let timestamp = new Date().getTime() // 時間戳
   let url = req.query.url  // 使用接口的url鏈接,不包含#后的內(nèi)容

   // 將請求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此處直接手動排序
   let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '&timestamp=' + timestamp + '&url=' + url

   // 用sha1加密
   let signature = sha1(str)
 })
})

曝露接口,返回給前端

app.post('/wxJssdk/getJssdk', (req, res) => {
 const request = require('request')

 const grant_type = 'client_credential'
 const appid = 'your app id'
 const secret = 'your app secret'

 request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {
  let access_toekn = JSON.parse(body).access_token

  request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => {
    let jsapi_ticket = JSON.parse(body).ticket
    let nonce_str = '123456'  // 密鑰,字符串任意,可以隨機生成
    let timestamp = new Date().getTime() // 時間戳
    let url = req.query.url  // 使用接口的url鏈接,不包含#后的內(nèi)容

    // 將請求以上字符串,先按字典排序,再以'&'拼接,如下:其中j > n > t > u,此處直接手動排序
    let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '&timestamp=' + timestamp + '&url=' + url

    // 用sha1加密
    let signature = sha1(str)

    res.send({
     appId: appid,
     timestamp: timpstamp,
     nonceStr: nonce_str,
     signature: signature,
    })
  })
 })
})

前端請求后端接口,獲取配置信息

獲取配置

axios.post('/wxJssdk/getJssdk', {url: location.href}).then((response) => {
 var data = response.data

 wx.config({
  debug: false, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會通過log打出,僅在pc端時才會打印。
  appId: data.appId, // 必填,公眾號的唯一標(biāo)識
  timestamp: data.timestamp, // 必填,生成簽名的時間戳
  nonceStr: data.nonceStr, // 必填,生成簽名的隨機串
  signature: data.signature,// 必填,簽名,見附錄1
  jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
 });

})

做你想做的,比如,自定義分享

if (wx) {
 axios.post('/wxJssdk/getJssdk', {url: location.href}).then((response) => {
  var data = response.data

  wx.config({
   debug: false, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會通過log打出,僅在pc端時才會打印。
   appId: data.appId, // 必填,公眾號的唯一標(biāo)識
   timestamp: data.timestamp, // 必填,生成簽名的時間戳
   nonceStr: data.nonceStr, // 必填,生成簽名的隨機串
   signature: data.signature,// 必填,簽名,見附錄1
   jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage'] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
  });

  wx.ready(function () {
   wx.onMenuShareTimeline({
   title: wxShare.title,
   desc: wxShare.desc,
   link: wxShare.link,
   imgUrl: wxShare.imgUrl
   });

   wx.onMenuShareAppMessage({
   title: wxShare.title,
   desc: wxShare.desc,
   link: wxShare.link,
   imgUrl: wxShare.imgUrl
  });
 })

  wx.error(function (res) {
    // config信息驗證失敗會執(zhí)行error函數(shù),如簽名過期導(dǎo)致驗證失敗,具體錯誤信息可以打開config的debug模式查看,也可以在返回的res參數(shù)中查看,對于SPA可以在這里更新簽名。
  })
 })

}

至此,后端配置好了,我們已經(jīng)能夠正常使用微信的接口了,但是微信每日接口請求是有上限的,通過2000次/天,因此如果網(wǎng)站上線后,一量當(dāng)天訪問量超過2000次你的接口將失效,而且每次都請求微信接口兩次,造成請求時間浪費,所以我們需要將以上獲取信息緩存在后端,避免造成接口失效以及多次請求微信后臺。

緩存access_token及jsapi_ticket

此處直接上代碼,利用node_cache包進(jìn)行緩存

const request = require('request')
const express = require('express')
const app = express()
const sha1 = require('sha1')
const waterfall = require('async/waterfall')
const NodeCache = require('node-cache')
const cache = new NodeCache({stdTTL: 3600, checkperiod: 3600}) //3600秒后過過期

app.get('/wxJssdk', (req, res) => {
 let wx = req.query

 // 1)將token、timestamp、nonce三個參數(shù)進(jìn)行字典序排序
 let token = 'jegfjaeghfuyawegfgjdbh'
 let timestamp = wx.timestamp
 let nonce = wx.nonce

 // 2)將三個參數(shù)字符串拼接成一個字符串進(jìn)行sha1加密
 let list = [token, timestamp, nonce]
 let result = sha1(list.sort().join(''))

 // 3)開發(fā)者獲得加密后的字符串可與signature對比,標(biāo)識該請求來源于微信
 if (result === wx.signature) {
  res.send(wx.echostr)
 } else {
  res.send(false)
 }
})

app.get('/wxJssdk/getJssdk', (req, res) => {
 let grant_type = 'client_credential'
 let appid = 'your app id'
 let secret = 'your app secret' // appscret

 let steps = []

 // 第一步,獲取access_token
 steps.push((cb) => {

 let steps1 = []

  // 第1.1步,從緩存中讀取access_token
  steps1.push((cb1) => {
   let access_token = cache.get('access_token', (err, access_token) => {
    cb1(err, access_token)
   })
  })

  // 第1.2步,緩存中有access_token則直接返回,如果沒有,則從服務(wù)器中讀取access_token
  steps1.push((access_token, cb1) => {
   if (access_token) {
    cb1(null, access_token, 'from_cache')
   } else {
    request('https://api.weixin.qq.com/cgi-bin/token?grant_type=' + grant_type + '&appid=' + appid + '&secret=' + secret, (err, response, body) => {
     cb1(err, JSON.parse(body).access_token, 'from_server')
    })
   }
  })

  // 第1.3步,如果是新從服務(wù)器取的access_token,則緩存起來,否則直接返回
  steps1.push((access_token, from_where, cb1) => {
   if (from_where === 'from_cache') {
    console.log(' === 成功從緩存中讀取access_token: ' + access_token + ' ===')
    cb1(null, access_token)
   } else if (from_where === 'from_server') {
    cache.set('access_token', access_token, (err, success) => {
     if (!err && success) {
      console.log(' === 緩存已過期,從服務(wù)器中讀取access_token: ' + access_token + ' ===')
      cb1(null, access_token)
     } else {
      cb1(err || 'cache設(shè)置access_token時,出現(xiàn)未知錯誤')
     }
    })
   } else {
    cb1('1.3獲取from_where時,from_where值為空')
   }
  })



  waterfall(steps1, (err, access_token) => {
   cb(err, access_token)
  })
 })


 // 第二步,獲取ticket
 steps.push((access_token, cb) => {
  let steps1 = []

  // 第2.1步,從緩存中讀取ticket
  steps1.push((cb1) => {
   let ticket = cache.get('ticket', (err, ticket) => {
    cb1(err, ticket)
   })
  })

  // 第2.2步,緩存中有ticket則直接返回,如果沒有,則從服務(wù)器中讀取ticket
  steps1.push((ticket, cb1) => {
   if (ticket) {
    cb1(null, ticket, 'from_cache')
   } else {
    request('https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token + '&type=jsapi', (err, response, body) => {
     cb1(err, JSON.parse(body).ticket, 'from_server')
    })
   }
  })

  // 第2.3步,如果新從服務(wù)器取的ticket,則緩存起來,否則直接返回
  steps1.push((ticket, from_where, cb1) => {
   if (from_where === 'from_cache') {
    console.log(' === 成功從緩存中讀取ticket: ' + ticket + ' ===')
    cb1(null, ticket)
   } else if (from_where === 'from_server') {
    cache.set('ticket', ticket, (err, success) => {
     if (!err && success) {
      console.log(' === 緩存已過期,從服務(wù)器中讀取ticket: ' + ticket + ' ===');
      cb1(null, ticket)
     } else {
      cb1(err || 'cache設(shè)置ticket時,出現(xiàn)未知錯誤')
     }
    })
   } else {
    cb1('2.3獲取from_where時,from_where值為空')
   }
  })

  waterfall(steps1, (err, ticket) => {
   cb(err, ticket)
  })
 })


 // 第三步,生成簽名
 steps.push((ticket, cb) => {
  let jsapi_ticket = ticket
  let nonce_str = '123456'
  let timestamp = new Date().getTime()
  let url = req.query.url

  let str = 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + nonce_str + '&timestamp=' + timestamp + '&url=' + url
  let signature = sha1(str)

  cb(null, {
   appId: appid,
   timestamp: timestamp,
   nonceStr: nonce_str,
   signature: signature,
   ticket: ticket
  })
 })

 waterfall(steps, (err, data) => {
  if (err) {
   res.send({status: 'error', data: err})
  } else {
   res.send({status: 'success', data: data})
  }
 })
})

app.use('/wxJssdk/public', express.static('public'))

app.listen(80, err => {
 if(!err) console.log('connect succeed')
})

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Node.js 制作實時多人游戲框架

    Node.js 制作實時多人游戲框架

    這篇文章主要介紹了Node.js 制作實時多人游戲框架,需要的朋友可以參考下
    2015-01-01
  • node.js中的path.resolve方法使用說明

    node.js中的path.resolve方法使用說明

    這篇文章主要介紹了node.js中的path.resolve方法使用說明,本文介紹了path.resolve的方法說明、接收參數(shù)、語法、使用實例和實現(xiàn)源碼,需要的朋友可以參考下
    2014-12-12
  • 使用Node.js實現(xiàn)一個簡單的命令行工具

    使用Node.js實現(xiàn)一個簡單的命令行工具

    這篇文章主要為大家詳細(xì)介紹了如何用 Node.js 實現(xiàn)一個簡單的命令行工具,模仿常用的 ls 命令,包括其 -a 和 -l 參數(shù)的功能,感興趣的可以了解下
    2024-11-11
  • nodejs實現(xiàn)文件或文件夾上傳功能的代碼示例

    nodejs實現(xiàn)文件或文件夾上傳功能的代碼示例

    在平常的工作中,經(jīng)常會遇到需要將本地項目文件同步到遠(yuǎn)端服務(wù)器的情況,所以每次遇到都需要考慮如何將文件上傳到服務(wù)器上,所以本文就給大家介紹一下nodejs實現(xiàn)文件或文件夾上傳功能,需要的朋友可以參考下
    2023-08-08
  • 解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運行的程序

    解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運行的程序

    最近在工作中遇到了個常見的問題,分享給大家,這篇文章主要給大家介紹了關(guān)于如何解決使用node命令提示:'node'不是內(nèi)部或外部命令,也不是可運行的程序的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • windows實現(xiàn)npm和cnpm安裝步驟

    windows實現(xiàn)npm和cnpm安裝步驟

    這篇文章主要介紹了windows實現(xiàn)npm和cnpm安裝步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 詳解nodeJS之路徑PATH模塊

    詳解nodeJS之路徑PATH模塊

    本篇文章主要介紹了詳解nodeJS之路徑PATH模塊 ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 使用nvm管理不同版本的node與npm的方法

    使用nvm管理不同版本的node與npm的方法

    本篇文章主要介紹了使用 nvm 管理不同版本的 node 與 npm的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • 如何使用 Node.js 實現(xiàn)一個上傳圖片接口

    如何使用 Node.js 實現(xiàn)一個上傳圖片接口

    本文介紹了如何使用Node.js和Express框架創(chuàng)建一個簡單的上傳圖片接口,首先,通過npm初始化項目并安裝必要的依賴,如express和multer,然后,在index.js文件中編寫上傳圖片的邏輯,并通過Postman測試接口,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • node.js制作一個簡單的登錄攔截器

    node.js制作一個簡單的登錄攔截器

    本文給大家分享的是使用node.js制作一個簡單的登錄攔截的思路及代碼,有需要的小伙伴可以參考下
    2020-02-02

最新評論

江城| 金坛市| 来宾市| 济阳县| 喀什市| 辽阳县| 道孚县| 柳河县| 邵阳市| 甘德县| 武城县| 临安市| 岚皋县| 襄汾县| 保德县| 寿阳县| 舒兰市| 北辰区| 视频| 子长县| 高邑县| 腾冲县| 竹北市| 如东县| 工布江达县| 普定县| 惠东县| 进贤县| 泗水县| 当阳市| 儋州市| 当阳市| 宁河县| 德州市| 定结县| 武城县| 赤壁市| 涡阳县| 加查县| 娄烦县| 巴楚县|