日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

手把手帶你用 82 行代碼實(shí)現(xiàn)一個(gè)簡易版 Express 框架

來源: 責(zé)編: 時(shí)間:2024-02-06 10:09:34 382觀看
導(dǎo)讀本文將帶大家實(shí)現(xiàn)輕量級 web 框架 connect[1] 的主要功能,只要 82 行代碼就能搞定。我并沒有標(biāo)題黨,因?yàn)?Express 在 v3 版本之前就是基于 connect 進(jìn)行封裝的,不過在 v4 版本就將 connect 依賴移除了[2],代碼被搬到 Expr

本文將帶大家實(shí)現(xiàn)輕量級 web 框架 connect[1] 的主要功能,只要 82 行代碼就能搞定。vYE28資訊網(wǎng)——每日最新資訊28at.com

我并沒有標(biāo)題黨,因?yàn)?Express 在 v3 版本之前就是基于 connect 進(jìn)行封裝的,不過在 v4 版本就將 connect 依賴移除了[2],代碼被搬到 Express 倉庫里,并做了一些細(xì)微調(diào)整。因此某種程度上,學(xué)習(xí) connect 就是在學(xué)習(xí) Express。vYE28資訊網(wǎng)——每日最新資訊28at.com

connect 的 repo 描述是:“Connect is a middleware layer for Node.js”,也就是一個(gè) Node.js 的中間件層。中間件層是一個(gè)非常有用的機(jī)制,它類似一個(gè)插件系統(tǒng),讓我們可以通過插拔的方式組合不同功能來處理請求。vYE28資訊網(wǎng)——每日最新資訊28at.com

基本使用

先來看看 connect 的使用。vYE28資訊網(wǎng)——每日最新資訊28at.com

const connect = require('connect')const app = connect()// respond to all requestsapp.use(function(req, res){  res.end('Hello from Connect!/n')})// create node.js http server and listen on porthttp.createServer(app).listen(3000)

跟 Express 一樣。vYE28資訊網(wǎng)——每日最新資訊28at.com

另外,app 上還提供了 .listen() 方法,用于替代 http.createServer(app).listen(3000) 的冗長寫法。vYE28資訊網(wǎng)——每日最新資訊28at.com

app.listen(3000) // 等價(jià)于 http.createServer(app).listen(3000)

再看看中間件的使用。vYE28資訊網(wǎng)——每日最新資訊28at.com

app.use(function middleware1(req, res, next) {  // middleware 1  next()});app.use(function middleware2(req, res, next) {  // middleware 2  next()});

我們通過 app.use() 方法收集并使用中間件。vYE28資訊網(wǎng)——每日最新資訊28at.com

中間件就是一個(gè)函數(shù),包含 3 個(gè)參數(shù):req、res 還有 next()。在一個(gè)中間件內(nèi)調(diào)用 next(),就進(jìn)入到下一個(gè)中間件的執(zhí)行。vYE28資訊網(wǎng)——每日最新資訊28at.com

同時(shí),我們還可以為中間件指定路由,這樣中間件只在特定路徑下起作用。vYE28資訊網(wǎng)——每日最新資訊28at.com

app.use('/foo', function fooMiddleware(req, res, next) {  // req.url starts with "/foo"  next()})app.use('/bar', function barMiddleware(req, res, next) {  // req.url starts with "/bar"  next()})

本質(zhì)上,純中間件的寫法就是在設(shè)置根路由('/'),所以會對所有請求有效。vYE28資訊網(wǎng)——每日最新資訊28at.com

app.use(function middleware1(req, res, next) {  // middleware 1  next()})// 等同于app.use('/', function middleware1(req, res, next) {  // middleware 1  next()})

不過還有一類特殊中間件——異常中間件,專門用于處理前面流程里的異常錯(cuò)誤。vYE28資訊網(wǎng)——每日最新資訊28at.com

// regular middlewareapp.use(function (req, res, next) {  // i had an error  next(new Error('boom!'));});// error middleware for errors that occurred in middleware// declared before thisapp.use(function onerror(err, req, res, next) {  // an error occurred!});

異常中間件必須是 4 個(gè)參數(shù),第一個(gè)參數(shù)就是 error,對應(yīng)前面流程中傳遞給 next() 的 Error 對象。vYE28資訊網(wǎng)——每日最新資訊28at.com

以上,我們就講完了 connect 庫的基本使用。接下來,就著手實(shí)現(xiàn)。vYE28資訊網(wǎng)——每日最新資訊28at.com

代碼實(shí)現(xiàn)

基于 connect v3.7.0 版本[3]。vYE28資訊網(wǎng)——每日最新資訊28at.com

剛學(xué) Node.js 的時(shí)候,我們學(xué)到第一個(gè)例子,可能就是啟動一個(gè)會說“Hello World”的服務(wù)器了。vYE28資訊網(wǎng)——每日最新資訊28at.com

const http = require('node:http')const hostname = '127.0.0.1'const port = 3000const server = http.createServer((req, res) => {  res.statusCode = 200  res.setHeader('Content-Type', 'text/plain')  res.end('Hello World/n')})server.listen(port, hostname, () => {  console.log(`Server running at http://${hostname}:${port}/`)})

回顧 connect 的使用。vYE28資訊網(wǎng)——每日最新資訊28at.com

const connect = require('connect')const app = connect()// respond to all requestsapp.use(function(req, res){  res.end('Hello from Connect!/n')})// create node.js http server and listen on portapp.listen(3000)

實(shí)現(xiàn) app.listen()

我們已經(jīng)知道 app.listen(3000) 內(nèi)部實(shí)現(xiàn)就是 http.createServer(app).listen(3000)。vYE28資訊網(wǎng)——每日最新資訊28at.com

因此,我們先實(shí)現(xiàn) .listen() 方法。vYE28資訊網(wǎng)——每日最新資訊28at.com

module.exports = function createApplication() {  const app = {}  app.listen = function listen(...args) {    const server = require('node:http').createServer(/* ? */)    return server.listen(...args);  }  return app}

假設(shè) app 是一個(gè)對象。不過,http.createServer(/* ? */) 中的 ? 內(nèi)容該如何實(shí)現(xiàn)呢?vYE28資訊網(wǎng)——每日最新資訊28at.com

實(shí)現(xiàn) app.use()

前一步,我們做了 app.use() 的調(diào)用。vYE28資訊網(wǎng)——每日最新資訊28at.com

// respond to all requestsapp.use(function(req, res){  res.end('Hello from Connect!/n')})

所以,當(dāng)服務(wù)啟動后,訪問 localhost:3000 時(shí),應(yīng)該返回 "Hello from Connect!" 的文本。vYE28資訊網(wǎng)——每日最新資訊28at.com

同時(shí),app.use() 又支持重復(fù)調(diào)用。vYE28資訊網(wǎng)——每日最新資訊28at.com

// respond to all requestsapp.use(function(req, res, next) {  console.log('log req.url', req.url)  next()})// respond to all requestsapp.use(function(req, res) {  res.end('Hello from Connect!/n')})

那我們就考慮先用個(gè)數(shù)組,把通過 app.use() 調(diào)用傳入進(jìn)來的回調(diào)函數(shù)存起來。vYE28資訊網(wǎng)——每日最新資訊28at.com

module.exports = function createApplication() {  const app = {} app.stack = []    app.use = function use(route, fn) {   let path = route   let handle = fn        // default route to '/'   if (typeof route !== 'string') {      path = '/'      handle = route    }        this.stack.push({ route: path, handle })    return this  }    app.listen = function listen(...args) {    const server = require('node:http').createServer(/* ? */)    return server.listen(...args)  }  return app}

我們把調(diào)用 app.use() 傳入的中間件都存到了 app.stack 里。vYE28資訊網(wǎng)——每日最新資訊28at.com

根據(jù)定義可知,http.createServer(/* ? */) 中的 ? 內(nèi)容應(yīng)該是一個(gè)函數(shù)。針對當(dāng)前場景,它是用來處理 stack 中的這些中間件的。vYE28資訊網(wǎng)——每日最新資訊28at.com

實(shí)現(xiàn) app.handle()

我們把這些邏輯寫在 app.handle() 內(nèi)。vYE28資訊網(wǎng)——每日最新資訊28at.com

module.exports = function createApplication() {  const app = {}  app.stack = []  // ...  app.listen = function listen(...args) {    const server = require('node:http').createServer(app.handle.bind(app))    return server.listen(...args)  }  app.handle = function handle(res, res) {    // TODO  }  return app}

每當(dāng)請求來臨,都由 app.handle 負(fù)責(zé)處理。vYE28資訊網(wǎng)——每日最新資訊28at.com

app.handle 的主要邏輯主要是處理 3 件事情。vYE28資訊網(wǎng)——每日最新資訊28at.com

  1. 獲取當(dāng)前要處理的路由,沒有的話就交由最終處理函數(shù) done
  2. 路由不匹配就跳過
  3. 路由匹配就執(zhí)行當(dāng)前中間件
app.handle = function handle(req, res) {  let index = 0  const done = function (err) { /* ... */ }  function next(err) {    // next callback    const layer = app.stack[index++]    // 1) all done    if (!layer) {      setImmdiate(done, err)      return    }    // route data    const path = require('node:url').parse(req.url).pathname    const route = layer.route    // 2) skip this layer if the route doesn't match    if (!path.toLowerCase().startsWith(route.toLowerCase())) {      return next(err)    }    // 3) call the layer handle    const arity = handle.length    const hasError = !!err    let error = err    try {      if (hasError && arity === 4) {        // error-handling middleware        layer.handle(err, req, res, next)        return      } else if (!hasError && arity < 4) {        // request-handling middleware        layer.handle(req, res, next)        return      }    } catch (e) {      error = e    }    next(error)  }  next()}

以上的關(guān)鍵處理就封裝在 next() 函數(shù)中。而 next() 函數(shù)就是傳遞給 connect 中間件的 next 參數(shù)。vYE28資訊網(wǎng)——每日最新資訊28at.com

這樣,每次請求進(jìn)來,我們都會從 app.stack 的第一個(gè)中間件(stack[0])開始處理,就實(shí)現(xiàn)了以 next 參數(shù)為連接橋梁的中間件機(jī)制。vYE28資訊網(wǎng)——每日最新資訊28at.com

值得注意的是調(diào)用當(dāng)前中間件的邏輯,當(dāng)我們調(diào)用 layer.handle(err, req, res, next)/layer.handle(req, res, next) 時(shí),處理流程會流入中間件內(nèi)部,當(dāng)內(nèi)部調(diào)用 next() 函數(shù)后,控制權(quán)會重新回到 app.handle,繼續(xù)處理隊(duì)列中的下一個(gè)中間件。vYE28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)請求最終沒有任何中間件可以處理時(shí),就會流入到 done,這是最終處理器。處理器內(nèi)部,會根據(jù)是否存在錯(cuò)誤,分別返回 404 或 5xx 響應(yīng)。vYE28資訊網(wǎng)——每日最新資訊28at.com

const done = function (err) {  if (err) {    res.statusCode = err.status ?? err.statusCode ?? 500    res.statusMessage = require('node:http').STATUS_CODES[404]  } else {    res.statusCode = 404    res.statusMessage = `Cannot ${req.method} ${require('node:url').parse(req.url).pathname}`  }  res.end(`${res.statusCode} ${res.statusMessage}`)}

至此,我們基本寫完了所有的邏輯。vYE28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)然,有一個(gè)地方,可以做一個(gè)小小的優(yōu)化。將 http.createServer(app.handle.bind(app)) 簡化成 http.createServer(this),不過此時(shí) app 就不能是對象,而是函數(shù)了。vYE28資訊網(wǎng)——每日最新資訊28at.com

module.exports = function createApplication() { function app(req, res) { app.handle(req, res) }  // ...    app.listen = function listen(...args) {    const server = require('node:http').createServer(app)    return server.listen(...args)  }  // ...   return app}

最后,我們整體來回顧一下。vYE28資訊網(wǎng)——每日最新資訊28at.com

module.exports = function createApplication() {  function app(req, res) { app.handle(req, res) }  app.stack = []  app.use = function use(route, fn) {    let path = route    let handle = fn        // default route to '/'    if (typeof route !== 'string') {      path = '/'      handle = route    }    this.stack.push({ route: path, handle })    return this  }  app.listen = function listen(...args) {    const server = require('node:http').createServer(app)    return server.listen(...args)  }  app.handle = function handle(req, res) {    let index = 0    const done = function (err) {      if (err) {        res.statusCode = err.status ?? err.statusCode ?? 500        res.statusMessage = require('node:http').STATUS_CODES[404]      } else {        res.statusCode = 404        res.statusMessage = `Cannot ${req.method} ${require('node:url').parse(req.url).pathname}`      }      res.end(`${res.statusCode} ${res.statusMessage}`)    }    function next(err) {      // next callback      const layer = app.stack[index++]      // 1) all done      if (!layer) {        setImmediate(done, err)        return      }      const path = require('node:url').parse(req.url).pathname      const route = layer.route            // 2) skip this layer if the route doesn't match      if (!path.toLowerCase().startsWith(route.toLowerCase())) {        return next(err)      }      // 3) call the layer handle      const arity = handle.length      const hasError = !!err      let error = err      try {        // error-handling middleware        if (hasError && arity === 4) {          layer.handle(err, req, res, next)          return        // request-handling middleware        } else if (!hasError && arity < 4) {           layer.handle(req, res, next)          return        }      } catch (e) {        error = e      }      next(error)    }    next()  }    return app}

連上注釋,我們只用了 82 行代碼,就實(shí)現(xiàn)了 connect 的主要功能。vYE28資訊網(wǎng)——每日最新資訊28at.com

vYE28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)

本文帶大家實(shí)現(xiàn)了輕量級 Web 框架 connect 的主要功能,同樣這也是一個(gè)簡易版本  Express!vYE28資訊網(wǎng)——每日最新資訊28at.com

實(shí)現(xiàn)核心是 2 個(gè)函數(shù)。vYE28資訊網(wǎng)——每日最新資訊28at.com

  • app.use(route, fn):用于收集中間件
  • app.handle(res, req):用于消費(fèi)中間件。主要邏輯位于 next() 函數(shù),這是傳遞給中間件的 next 參數(shù)。每一次接收請求來臨時(shí),都由 app.handle 負(fù)責(zé)處理

而這兩個(gè)函數(shù)之間的橋梁就是 app.stack。vYE28資訊網(wǎng)——每日最新資訊28at.com

行文最后,給大家留一個(gè)思考題。vYE28資訊網(wǎng)——每日最新資訊28at.com

connect() 實(shí)例的真實(shí)實(shí)現(xiàn),是支持作為子應(yīng)用,掛載到父應(yīng)用之上的,也就是下面的用法。vYE28資訊網(wǎng)——每日最新資訊28at.com

const connect = require('connect')const app = connect()const blogApp = connect()app.use('/blog', blogApp)app.listen(3000)

甚至 http.Server 實(shí)例也支持掛載。vYE28資訊網(wǎng)——每日最新資訊28at.com

const connect = require('connect')const app = connect()const blog = http.createServer(function(req, res){  res.end('blog')})app.use('/blog', blog)

那是如何實(shí)現(xiàn)呢?vYE28資訊網(wǎng)——每日最新資訊28at.com

大家可以參照 app.use()[4] 函數(shù)的源碼進(jìn)行學(xué)習(xí)。vYE28資訊網(wǎng)——每日最新資訊28at.com

感謝的你的閱讀,再見~vYE28資訊網(wǎng)——每日最新資訊28at.com

參考資料

[1]connect: https://github.com/senchalabs/connectvYE28資訊網(wǎng)——每日最新資訊28at.com

[2]在 v4 版本就將 connect 依賴移除了: https://github.com/expressjs/express/compare/3.21.2...4.0.0#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519vYE28資訊網(wǎng)——每日最新資訊28at.com

[3]connect v3.7.0 版本: https://github.com/senchalabs/connect/blob/3.7.0/index.jsvYE28資訊網(wǎng)——每日最新資訊28at.com

[4]app.use(): https://github.com/senchalabs/connect/blob/3.7.0/index.js#L76vYE28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-74660-0.html手把手帶你用 82 行代碼實(shí)現(xiàn)一個(gè)簡易版 Express 框架

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 「鵝來運(yùn)轉(zhuǎn) 新春添囍」!小天鵝為爾濱投送龍年新囍福利!

下一篇: 從 0 開始用 PyTorch 構(gòu)建完整的 NeRF

標(biāo)簽:
  • 熱門焦點(diǎn)
  • 一加Ace2 Pro真機(jī)揭曉 鈦空灰配色質(zhì)感拉滿

    終于,在經(jīng)過了幾波預(yù)熱之后,一加Ace2 Pro的外觀真機(jī)圖在網(wǎng)上出現(xiàn)了。還是博主數(shù)碼閑聊站曝光的,這次的外觀設(shè)計(jì)還是延續(xù)了一加11的方案,只是細(xì)節(jié)上有了調(diào)整,例如新加入了鈦空灰
  • 容量越大越不壞?24萬塊硬盤故障率報(bào)告公布 這些產(chǎn)品零故障

    8月5日消息,云存儲服務(wù)商Backblaze發(fā)布了最新的硬盤故障率報(bào)告,年故障率有所上升。Backblaze發(fā)布的硬盤季度統(tǒng)計(jì)數(shù)據(jù),其中包括故障率等重要方面。這些結(jié)
  • 服務(wù)存儲設(shè)計(jì)模式:Cache-Aside模式

    Cache-Aside模式一種常用的緩存方式,通常是把數(shù)據(jù)從主存儲加載到KV緩存中,加速后續(xù)的訪問。在存在重復(fù)度的場景,Cache-Aside可以提升服務(wù)性能,降低底層存儲的壓力,缺點(diǎn)是緩存和底
  • JavaScript學(xué)習(xí) -AES加密算法

    引言在當(dāng)今數(shù)字化時(shí)代,前端應(yīng)用程序扮演著重要角色,用戶的敏感數(shù)據(jù)經(jīng)常在前端進(jìn)行加密和解密操作。然而,這樣的操作在網(wǎng)絡(luò)傳輸和存儲中可能會受到惡意攻擊的威脅。為了確保數(shù)據(jù)
  • 微軟邀請 Microsoft 365 商業(yè)用戶,測試視頻編輯器 Clipchamp

    8 月 1 日消息,微軟近日宣布即將面向 Microsoft 365 商業(yè)用戶,開放 Clipchamp 應(yīng)用,邀請用戶通過該應(yīng)用來編輯視頻。微軟于 2021 年收購 Clipchamp,隨后開始逐步整合到 Microsof
  • 2023年,我眼中的字節(jié)跳動

    此時(shí)此刻(2023年7月),字節(jié)跳動從未上市,也從未公布過任何官方的上市計(jì)劃;但是這并不妨礙它成為中國最受關(guān)注的互聯(lián)網(wǎng)公司之一。從2016-17年的抖音強(qiáng)勢崛起,到2018年的&ldquo;頭騰
  • 中國家電海外掘金正當(dāng)時(shí)|出海專題

    作者|吳南南編輯|胡展嘉運(yùn)營|陳佳慧出品|零態(tài)LT(ID:LingTai_LT)2023年,出海市場戰(zhàn)況空前,中國創(chuàng)業(yè)者在海外紛紛摩拳擦掌,以期能夠把中國的商業(yè)模式、創(chuàng)業(yè)理念、戰(zhàn)略打法輸出海外,他們依
  • 華為Mate 60保護(hù)殼曝光:碩大后置相機(jī)模組 凸起程度有驚喜

    這段時(shí)間以來,關(guān)于華為新旗艦的爆料日漸密集。據(jù)此前多方爆料,今年華為將開始恢復(fù)一年雙旗艦戰(zhàn)略,除上半年推出的P60系列外,往年下半年的Mate系列也將
  • AMD的AI芯片轉(zhuǎn)單給三星可能性不大 與臺積電已合作至2nm制程

    據(jù) DIGITIMES 消息,英偉達(dá) AI GPU 出貨逐季飆升,接下來 AMD MI 300 系列將在第 4 季底量產(chǎn)。而半導(dǎo)體業(yè)內(nèi)人士表示,近日傳出 AMD 的 AI 芯片將轉(zhuǎn)單給
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
国产精品视频yy9299一区| 一区二区三区国产在线| 国产精品自拍三区| 国内自拍一区| 亚洲巨乳在线| 亚洲欧美日韩精品| 久久亚洲精品伦理| 欧美激情一级片一区二区| 欧美午夜一区二区福利视频| 国产欧美日本| 亚洲国产美女精品久久久久∴| 洋洋av久久久久久久一区| 欧美亚洲一区三区| 欧美a级理论片| 国产精品区二区三区日本 | 欧美三区在线| 国产综合色在线视频区| 亚洲免费激情| 久久国产精品99国产精| 欧美精品一区二区三区四区 | 一区在线影院| 亚洲午夜视频在线| 快射av在线播放一区| 欧美三日本三级少妇三2023| 国产一区二区三区直播精品电影| 亚洲卡通欧美制服中文| 久久久久成人精品免费播放动漫| 欧美日韩亚洲一区二区三区四区| 国内精品视频一区| 亚洲一卡久久| 欧美高清不卡| 国产一区二区三区高清播放| 一区二区激情小说| 久久午夜精品一区二区| 国产精品免费电影| 亚洲精品在线一区二区| 久久久久九九九九| 国产精品日韩精品欧美精品| 亚洲日本成人在线观看| 久久精品中文字幕一区二区三区| 欧美亚洲不卡| 亚洲精品字幕| 看欧美日韩国产| 国产一区清纯| 亚洲欧美日韩另类| 欧美视频在线观看视频极品| 亚洲欧洲日本mm| 久久亚洲私人国产精品va媚药| 国产老女人精品毛片久久| 一区二区三区视频在线看| 欧美大片国产精品| 在线观看日韩www视频免费 | 老司机午夜精品视频| 国产日韩欧美a| 亚洲一二区在线| 欧美日韩成人一区二区| 亚洲国产精品一区二区尤物区| 久久精品亚洲一区| 国产伦精品一区二区三区视频孕妇| 99精品视频免费| 欧美激情亚洲精品| 91久久精品网| 模特精品裸拍一区| 亚洲第一页在线| 久久久综合精品| 国产一区二区三区观看 | 欧美韩国日本综合| 亚洲第一页在线| 久热精品视频在线免费观看| 国产午夜精品一区二区三区欧美 | 久久九九精品99国产精品| 国产麻豆视频精品| 亚洲欧美日韩精品在线| 国产精品久久久久久久一区探花| 99国内精品| 欧美日韩日本网| 一本色道久久综合狠狠躁的推荐| 欧美日本一道本| 日韩亚洲在线观看| 欧美日韩一区国产| 亚洲性av在线| 国产精品五月天| 欧美一乱一性一交一视频| 国产欧美日韩激情| 久久黄色小说| 精品av久久久久电影| 久热精品视频在线| 91久久久久久| 欧美人与禽猛交乱配| 99综合视频| 国产精品国色综合久久| 亚洲欧美网站| 国产综合色产在线精品| 老司机精品视频一区二区三区| ●精品国产综合乱码久久久久| 蜜桃av一区二区| 亚洲伦理中文字幕| 国产精品porn| 久久国产精品黑丝| 在线日韩欧美| 欧美日韩国产在线一区| 亚洲一区二区av电影| 国产日本欧洲亚洲| 久久亚洲精选| 日韩午夜电影| 国产精品午夜视频| 久久精品中文字幕一区| 亚洲高清一二三区| 欧美日韩一区在线播放| 午夜精品福利视频| 狠狠干狠狠久久| 欧美精品在欧美一区二区少妇| 中国成人黄色视屏| 国产日韩精品视频一区二区三区| 久久久噜噜噜| 夜夜嗨av色一区二区不卡| 国产麻豆精品视频| 免费成人激情视频| 亚洲视频综合在线| 国产一区二三区| 欧美激情一区二区三区| 亚洲男人第一网站| 在线不卡中文字幕| 欧美午夜不卡| 久久免费高清| 在线亚洲美日韩| 激情六月婷婷久久| 欧美日韩一区二区国产| 欧美在线日韩精品| 亚洲欧洲一区二区天堂久久| 国产精品一区二区在线观看不卡| 久久中文字幕一区| 亚洲一区精品电影| 亚洲高清在线观看| 国产精品入口夜色视频大尺度| 乱人伦精品视频在线观看| 一区二区三区蜜桃网| 国内精品视频久久| 欧美三级视频在线| 久久一区亚洲| 亚洲欧美国产精品va在线观看| 在线观看欧美一区| 国产精品自在线| 欧美日韩国产成人在线| 久久精品二区| 亚洲午夜小视频| 亚洲欧洲日产国产网站| 国产曰批免费观看久久久| 欧美日韩一区二区三| 久久伊人亚洲| 午夜视频一区| 99re6这里只有精品视频在线观看| 国产亚洲一区二区三区在线播放| 欧美人与性动交cc0o| 久久久人成影片一区二区三区观看| 一区二区三区欧美亚洲| 亚洲二区在线观看| 国产一级一区二区| 国产精品福利网站| 欧美激情精品久久久久久蜜臀| 久久成人免费| 亚洲专区一二三| 亚洲乱码久久| 91久久线看在观草草青青| 黄色亚洲免费| 国产欧美一区二区精品忘忧草| 欧美日韩精品免费看| 免费成人在线观看视频| 久久久成人精品| 亚洲欧美中文日韩在线| 亚洲最黄网站| 亚洲毛片一区| 亚洲激情在线观看| 伊人久久久大香线蕉综合直播| 国产欧美亚洲一区| 国产精品毛片高清在线完整版| 欧美日韩国产成人在线观看| 欧美成黄导航| 久久尤物视频| 久久久免费精品视频| 欧美在线观看一区二区三区| 亚洲一区亚洲| 亚洲一级片在线观看| 一区二区三区四区五区精品| 91久久久久久久久久久久久| 亚洲高清三级视频| 在线观看日韩专区| 激情欧美丁香| 黄色另类av| 国产一区导航| 国产农村妇女毛片精品久久莱园子 | 在线精品视频免费观看| 国产综合av| 国内精品视频666| 黑人中文字幕一区二区三区 | 99国产精品国产精品久久| 亚洲日本激情| 亚洲精品乱码久久久久久| 最新日韩在线视频| 亚洲精品一区二区三区在线观看| 亚洲欧洲在线一区| 亚洲乱亚洲高清| 亚洲网站在线| 亚洲欧美综合国产精品一区|