Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产免费爽爽视频免费可以看,亚洲综合国产一区二区三区 ,在线观看一区二区三区视频

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          最簡單的 6 種防止數(shù)據(jù)重復(fù)提交的方法!(干貨)

          最簡單的 6 種防止數(shù)據(jù)重復(fù)提交的方法!(干貨)

          位朋友,某天突然問磊哥:在 Java 中,防止重復(fù)提交最簡單的方案是什么

          這句話中包含了兩個(gè)關(guān)鍵信息,第一:防止重復(fù)提交;第二:最簡單

          于是磊哥問他,是單機(jī)環(huán)境還是分布式環(huán)境?

          得到的反饋是單機(jī)環(huán)境,那就簡單了,于是磊哥就開始裝*了。

          話不多說,我們先來復(fù)現(xiàn)這個(gè)問題。

          模擬用戶場景

          根據(jù)朋友的反饋,大致的場景是這樣的,如下圖所示:

          簡化的模擬代碼如下(基于 Spring Boot):

          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          @RequestMapping("/user")
          @RestController
          public class UserController {
          /**
          * 被重復(fù)請求的方法
          */
          @RequestMapping("/add")
          public String addUser(String id) {
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          于是磊哥就想到:通過前、后端分別攔截的方式來解決數(shù)據(jù)重復(fù)提交的問題。

          前端攔截

          前端攔截是指通過 HTML 頁面來攔截重復(fù)請求,比如在用戶點(diǎn)擊完“提交”按鈕后,我們可以把按鈕設(shè)置為不可用或者隱藏狀態(tài)。

          執(zhí)行效果如下圖所示:

          前端攔截的實(shí)現(xiàn)代碼:

          <html>
          <script>
          function subCli{
          // 按鈕設(shè)置為不可用
          document.getElementById("btn_sub").disabled="disabled";
          document.getElementById("dv1").innerText="按鈕被點(diǎn)擊了~";
          }
          </script>
          <body style="margin-top: 100px;margin-left: 100px;">
          <input id="btn_sub" type="button" value=" 提 交 " onclick="subCli">
          <div id="dv1" style="margin-top: 80px;"></div>
          </body>
          </html>

          但前端攔截有一個(gè)致命的問題,如果是懂行的程序員或非法用戶可以直接繞過前端頁面,通過模擬請求來重復(fù)提交請求,比如充值了 100 元,重復(fù)提交了 10 次變成了 1000 元(瞬間發(fā)現(xiàn)了一個(gè)致富的好辦法)。

          所以除了前端攔截一部分正常的誤操作之外,后端的攔截也是必不可少。

          后端攔截

          后端攔截的實(shí)現(xiàn)思路是在方法執(zhí)行之前,先判斷此業(yè)務(wù)是否已經(jīng)執(zhí)行過,如果執(zhí)行過則不再執(zhí)行,否則就正常執(zhí)行。

          我們將請求的業(yè)務(wù) ID 存儲在內(nèi)存中,并且通過添加互斥鎖來保證多線程下的程序執(zhí)行安全,大體實(shí)現(xiàn)思路如下圖所示:

          然而,將數(shù)據(jù)存儲在內(nèi)存中,最簡單的方法就是使用 HashMap存儲,或者是使用 Guava Cache 也是同樣的效果,但很顯然HashMap可以更快的實(shí)現(xiàn)功能,所以我們先來實(shí)現(xiàn)一個(gè)HashMap的防重(防止重復(fù))版本。

          1.基礎(chǔ)版——HashMap

          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          import java.util.HashMap;
          import java.util.Map;

          /**
          * 普通 Map 版本
          */
          @RequestMapping("/user")
          @RestController
          public class UserController3 {

          // 緩存 ID 集合
          private Map<String, Integer> reqCache=new HashMap<>;

          @RequestMapping("/add")
          public String addUser(String id) {
          // 非空判斷(忽略)...
          synchronized (this.getClass) {
          // 重復(fù)請求判斷
          if (reqCache.containsKey(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return "執(zhí)行失敗";
          }
          // 存儲請求 ID
          reqCache.put(id, 1);
          }
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          實(shí)現(xiàn)效果如下圖所示:

          存在的問題:此實(shí)現(xiàn)方式有一個(gè)致命的問題,因?yàn)?code>HashMap是無限增長的,因此它會占用越來越多的內(nèi)存,并且隨著HashMap數(shù)量的增加查找的速度也會降低,所以我們需要實(shí)現(xiàn)一個(gè)可以自動“清除”過期數(shù)據(jù)的實(shí)現(xiàn)方案。

          2.優(yōu)化版——固定大小的數(shù)組

          此版本解決了 HashMap無限增長的問題,它使用數(shù)組加下標(biāo)計(jì)數(shù)器(reqCacheCounter)的方式,實(shí)現(xiàn)了固定數(shù)組的循環(huán)存儲。

          當(dāng)數(shù)組存儲到最后一位時(shí),將數(shù)組的存儲下標(biāo)設(shè)置 0,再從頭開始存儲數(shù)據(jù),實(shí)現(xiàn)代碼如下:

          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          import java.util.Arrays;

          @RequestMapping("/user")
          @RestController
          public class UserController {

          private static String reqCache=new String[100]; // 請求 ID 存儲集合
          private static Integer reqCacheCounter=0; // 請求計(jì)數(shù)器(指示 ID 存儲的位置)

          @RequestMapping("/add")
          public String addUser(String id) {
          // 非空判斷(忽略)...
          synchronized (this.getClass) {
          // 重復(fù)請求判斷
          if (Arrays.asList(reqCache).contains(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return "執(zhí)行失敗";
          }
          // 記錄請求 ID
          if (reqCacheCounter >=reqCache.length) reqCacheCounter=0; // 重置計(jì)數(shù)器
          reqCache[reqCacheCounter]=id; // 將 ID 保存到緩存
          reqCacheCounter++; // 下標(biāo)往后移一位
          }
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          3.擴(kuò)展版——雙重檢測鎖(DCL)

          上一種實(shí)現(xiàn)方法將判斷和添加業(yè)務(wù),都放入 synchronized中進(jìn)行加鎖操作,這樣顯然性能不是很高,于是我們可以使用單例中著名的 DCL(Double Checked Locking,雙重檢測鎖)來優(yōu)化代碼的執(zhí)行效率,實(shí)現(xiàn)代碼如下:

          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          import java.util.Arrays;

          @RequestMapping("/user")
          @RestController
          public class UserController {

          private static String reqCache=new String[100]; // 請求 ID 存儲集合
          private static Integer reqCacheCounter=0; // 請求計(jì)數(shù)器(指示 ID 存儲的位置)

          @RequestMapping("/add")
          public String addUser(String id) {
          // 非空判斷(忽略)...
          // 重復(fù)請求判斷
          if (Arrays.asList(reqCache).contains(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return "執(zhí)行失敗";
          }
          synchronized (this.getClass) {
          // 雙重檢查鎖(DCL,double checked locking)提高程序的執(zhí)行效率
          if (Arrays.asList(reqCache).contains(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return "執(zhí)行失敗";
          }
          // 記錄請求 ID
          if (reqCacheCounter >=reqCache.length) reqCacheCounter=0; // 重置計(jì)數(shù)器
          reqCache[reqCacheCounter]=id; // 將 ID 保存到緩存
          reqCacheCounter++; // 下標(biāo)往后移一位
          }
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          注意:DCL 適用于重復(fù)提交頻繁比較高的業(yè)務(wù)場景,對于相反的業(yè)務(wù)場景下 DCL 并不適用。

          4.完善版——LRUMap

          上面的代碼基本已經(jīng)實(shí)現(xiàn)了重復(fù)數(shù)據(jù)的攔截,但顯然不夠簡潔和優(yōu)雅,比如下標(biāo)計(jì)數(shù)器的聲明和業(yè)務(wù)處理等,但值得慶幸的是 Apache 為我們提供了一個(gè) commons-collections 的框架,里面有一個(gè)非常好用的數(shù)據(jù)結(jié)構(gòu) LRUMap可以保存指定數(shù)量的固定的數(shù)據(jù),并且它會按照 LRU 算法,幫你清除最不常用的數(shù)據(jù)。

          小貼士:LRU 是 Least Recently Used 的縮寫,即最近最少使用,是一種常用的數(shù)據(jù)淘汰算法,選擇最近最久未使用的數(shù)據(jù)予以淘汰。

          首先,我們先來添加 Apache commons collections 的引用:

           <!-- 集合工具類 apache commons collections -->
          <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
          <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-collections4</artifactId>
          <version>4.4</version>
          </dependency>

          實(shí)現(xiàn)代碼如下:

          import org.apache.commons.collections4.map.LRUMap;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          @RequestMapping("/user")
          @RestController
          public class UserController {

          // 最大容量 100 個(gè),根據(jù) LRU 算法淘汰數(shù)據(jù)的 Map 集合
          private LRUMap<String, Integer> reqCache=new LRUMap<>(100);

          @RequestMapping("/add")
          public String addUser(String id) {
          // 非空判斷(忽略)...
          synchronized (this.getClass) {
          // 重復(fù)請求判斷
          if (reqCache.containsKey(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return "執(zhí)行失敗";
          }
          // 存儲請求 ID
          reqCache.put(id, 1);
          }
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          使用了 LRUMap之后,代碼顯然簡潔了很多。

          5.最終版——封裝

          以上都是方法級別的實(shí)現(xiàn)方案,然而在實(shí)際的業(yè)務(wù)中,我們可能有很多的方法都需要防重,那么接下來我們就來封裝一個(gè)公共的方法,以供所有類使用:

          import org.apache.commons.collections4.map.LRUMap;

          /**
          * 冪等性判斷
          */
          public class IdempotentUtils {

          // 根據(jù) LRU(Least Recently Used,最近最少使用)算法淘汰數(shù)據(jù)的 Map 集合,最大容量 100 個(gè)
          private static LRUMap<String, Integer> reqCache=new LRUMap<>(100);

          /**
          * 冪等性判斷
          * @return
          */
          public static booleanjudge(String id, Object lockClass) {
          synchronized (lockClass) {
          // 重復(fù)請求判斷
          if (reqCache.containsKey(id)) {
          // 重復(fù)請求
          System.out.println("請勿重復(fù)提交!!!" + id);
          return false;
          }
          // 非重復(fù)請求,存儲請求 ID
          reqCache.put(id, 1);
          }
          return true;
          }
          }

          調(diào)用代碼如下:

          import com.example.idempote.util.IdempotentUtils;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;

          @RequestMapping("/user")
          @RestController
          public class UserController4 {
          @RequestMapping("/add")
          public String addUser(String id) {
          // 非空判斷(忽略)...
          // -------------- 冪等性調(diào)用(開始) --------------
          if (!IdempotentUtils.judge(id, this.getClass)) {
          return "執(zhí)行失敗";
          }
          // -------------- 冪等性調(diào)用(結(jié)束) --------------
          // 業(yè)務(wù)代碼...
          System.out.println("添加用戶ID:" + id);
          return "執(zhí)行成功!";
          }
          }

          小貼士:一般情況下代碼寫到這里就結(jié)束了,但想要更簡潔也是可以實(shí)現(xiàn)的,你可以通過自定義注解,將業(yè)務(wù)代碼寫到注解中,需要調(diào)用的方法只需要寫一行注解就可以防止數(shù)據(jù)重復(fù)提交了,老鐵們可以自行嘗試一下(需要磊哥擼一篇的,評論區(qū)留言 666)。

          擴(kuò)展知識——LRUMap 實(shí)現(xiàn)原理分析

          既然 LRUMap如此強(qiáng)大,我們就來看看它是如何實(shí)現(xiàn)的。

          LRUMap的本質(zhì)是持有頭結(jié)點(diǎn)的環(huán)回雙鏈表結(jié)構(gòu),它的存儲結(jié)構(gòu)如下:

          AbstractLinkedMap.LinkEntry entry;

          當(dāng)調(diào)用查詢方法時(shí),會將使用的元素放在雙鏈表 header 的前一個(gè)位置,源碼如下:

          public V get(Object key, boolean updateToMRU) {
          LinkEntry<K, V> entry=this.getEntry(key);
          if (entry==) {
          return ;
          } else {
          if (updateToMRU) {
          this.moveToMRU(entry);
          }

          return entry.getValue;
          }
          }
          protected voidmoveToMRU(LinkEntry<K, V> entry) {
          if (entry.after !=this.header) {
          ++this.modCount;
          if (entry.before==) {
          throw new IllegalStateException("Entry.before is . This should not occur if your keys are immutable, and you have used synchronization properly.");
          }

          entry.before.after=entry.after;
          entry.after.before=entry.before;
          entry.after=this.header;
          entry.before=this.header.before;
          this.header.before.after=entry;
          this.header.before=entry;
          } else if (entry==this.header) {
          throw new IllegalStateException("Can't move header to MRU This should not occur if your keys are immutable, and you have used synchronization properly.");
          }

          }

          如果新增元素時(shí),容量滿了就會移除 header 的后一個(gè)元素,添加源碼如下:

           protected void addMapping(int hashIndex, int hashCode, K key, V value) {
          // 判斷容器是否已滿
          if (this.isFull) {
          LinkEntry<K, V> reuse=this.header.after;
          boolean removeLRUEntry=false;
          if (!this.scanUntilRemovable) {
          removeLRUEntry=this.removeLRU(reuse);
          } else {
          while(reuse !=this.header && reuse !=) {
          if (this.removeLRU(reuse)) {
          removeLRUEntry=true;
          break;
          }
          reuse=reuse.after;
          }
          if (reuse==) {
          throw new IllegalStateException("Entry.after=, header.after=" + this.header.after + " header.before=" + this.header.before + " key=" + key + " value=" + value + " size=" + this.size + " maxSize=" + this.maxSize + " This should not occur if your keys are immutable, and you have used synchronization properly.");
          }
          }
          if (removeLRUEntry) {
          if (reuse==) {
          throw new IllegalStateException("reuse=, header.after=" + this.header.after + " header.before=" + this.header.before + " key=" + key + " value=" + value + " size=" + this.size + " maxSize=" + this.maxSize + " This should not occur if your keys are immutable, and you have used synchronization properly.");
          }
          this.reuseMapping(reuse, hashIndex, hashCode, key, value);
          } else {
          super.addMapping(hashIndex, hashCode, key, value);
          }
          } else {
          super.addMapping(hashIndex, hashCode, key, value);
          }
          }

          判斷容量的源碼:

          public boolean isFull {
          return size >=maxSize;
          }

          容量未滿就直接添加數(shù)據(jù):

          super.addMapping(hashIndex, hashCode, key, value);

          如果容量滿了,就調(diào)用 reuseMapping方法使用 LRU 算法對數(shù)據(jù)進(jìn)行清除。

          綜合來說:LRUMap的本質(zhì)是持有頭結(jié)點(diǎn)的環(huán)回雙鏈表結(jié)構(gòu),當(dāng)使用元素時(shí),就將該元素放在雙鏈表header的前一個(gè)位置,在新增元素時(shí),如果容量滿了就會移除header的后一個(gè)元素。

          總結(jié)

          本文講了防止數(shù)據(jù)重復(fù)提交的 6 種方法,首先是前端的攔截,通過隱藏和設(shè)置按鈕的不可用來屏蔽正常操作下的重復(fù)提交。但為了避免非正常渠道的重復(fù)提交,我們又實(shí)現(xiàn)了 5 個(gè)版本的后端攔截:HashMap 版、固定數(shù)組版、雙重檢測鎖的數(shù)組版、LRUMap 版和 LRUMap 的封裝版。

          特殊說明:本文所有的內(nèi)容僅適用于單機(jī)環(huán)境下的重復(fù)數(shù)據(jù)攔截,如果是分布式環(huán)境需要配合數(shù)據(jù)庫或 Redis 來實(shí)現(xiàn),想看分布式重復(fù)數(shù)據(jù)攔截的老鐵們,請給磊哥一個(gè)「」,如果點(diǎn)贊超過 100 個(gè),咱們更新分布式環(huán)境下重復(fù)數(shù)據(jù)的處理方案,謝謝你。

          參考 & 鳴謝

          https://blog.csdn.net/fenglllle/article/details/82659576

          -END-

          如果看到這里,說明你喜歡這篇文章,請 。同時(shí) 標(biāo)星(置頂)本公眾號可以第一時(shí)間接受到博文推送。

          最近整理一份面試資料《Java技術(shù)棧學(xué)習(xí)手冊》,覆蓋了Java技術(shù)、面試題精選、Spring全家桶、Nginx、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)、架構(gòu)等等。

          常開發(fā)中經(jīng)常會用到表單提交,如果表單沒有做防重復(fù)提交,可能會引起系統(tǒng)業(yè)務(wù)邏輯異常,導(dǎo)致系統(tǒng)數(shù)據(jù)錯(cuò)亂

          下面我給出一套常用的解決方案,前端用javascript鎖防止重復(fù)點(diǎn)擊,后端驗(yàn)證session里面的token值防止重復(fù)提交

          一、引起表單重復(fù)提交有以下幾種常見場景

          • 重復(fù)點(diǎn)擊提交按鈕。包括惡意的連續(xù)點(diǎn)擊提交按鈕,或因?yàn)榫W(wǎng)絡(luò)慢、服務(wù)器處理速度慢等引起的用戶多次點(diǎn)擊
          • 表單提交處理完后,通過瀏覽器的后退按鈕回到原頁面再次點(diǎn)擊提交按鈕
          • 通過點(diǎn)擊瀏覽器的刷新按鈕,導(dǎo)致表單重復(fù)提交
          • 通過瀏覽器的歷史記錄,獲取表單提交的URL地址,再次訪問

          二、前端

          session中設(shè)置一個(gè)token

          String token=UUID.randomUUID().toString();
          session.setAttribute("formToken", token);

          表單html

          <html>
          <head>
          <title>員工信息</title>
          </head>
          <body>
            <form method="post" action="/postForm">
              姓名:<input type="text" name="userName">
              年齡:<input type="text" name="age">
              性別:<input type="text" name="sex">
              <input type="hidden" name="formToken" value="${formToken}">
              <input type="button" value="保存" onclick="infoSave()">
            </form>
          </body>
          </html>

          js防止重復(fù)點(diǎn)擊

          <script>
          var isSaving=false;
          function infoSave() {
              if(isSaving) {
             		 return false;
              }
              isSaving=true;
              Ajax.post('https://xxx.xxx.xxx/infoSave',params).then(function(res){
                isSaving=false;
                if(res.code==200){
                	alert("修改成功");
                }else{
                	alert(res.message);
                }
                window.location.reload();
              });
          }
          </script>

          三、服務(wù)端

          String Token1=request.getParameter("formToken");
          String Token2=(String) session.getAttribute("formToken");
          if (Token1 !=null && Token1.equals(Token2)) {
            // 處理表單提交 ...
            // 刪除標(biāo)識符
            session.removeAttribute("formToken");
          }else{
          	// 重復(fù)提交,給出錯(cuò)誤提示
          } 

          四、總結(jié)

          一般情況下采用JS腳本方式和服務(wù)端方式兩種結(jié)合已可防止表單重復(fù)提交,針對特殊業(yè)務(wù)要求的可采用數(shù)據(jù)庫唯一性約束限制等方式來強(qiáng)制保證業(yè)務(wù)邏輯上的數(shù)據(jù)唯一要求。

          頁美工培訓(xùn)課程老師教你設(shè)置防止web表單重復(fù)提交的幾種策略,因?yàn)楸韱沃貜?fù)提交是在多用戶Web應(yīng)用中最常見、帶來很多麻煩的一個(gè)問題。有很多的應(yīng)用場景都會遇到重復(fù)提交問題,比如:

          點(diǎn)擊提交按鈕兩次。

          點(diǎn)擊刷新按鈕。

          使用瀏覽器后退按鈕重復(fù)之前的操作,導(dǎo)致重復(fù)提交表單。

          使用瀏覽器歷史記錄重復(fù)提交表單。

          瀏覽器重復(fù)的HTTP請求。

          幾種防止表單重復(fù)提交的方法

          禁掉提交按鈕。表單提交后使用Javascript使提交按鈕disable。這種方法防止心急的用戶多次點(diǎn)擊按鈕。但有個(gè)問題,如果客戶端把Javascript給禁止掉,這種方法就無效了。

          Post/Redirect/Get模式。在提交后執(zhí)行頁面重定向,這就是所謂的Post-Redirect-Get (PRG)模式。簡言之,當(dāng)用戶提交了表單后,你去執(zhí)行一個(gè)客戶端的重定向,轉(zhuǎn)到提交成功信息頁面。

          這能避免用戶按F5導(dǎo)致的重復(fù)提交,而其也不會出現(xiàn)瀏覽器表單重復(fù)提交的警告,也能消除按瀏覽器前進(jìn)和后退按導(dǎo)致的同樣問題。

          在session中存放一個(gè)特殊標(biāo)志。當(dāng)表單頁面被請求時(shí),生成一個(gè)特殊的字符標(biāo)志串,存在session中,同時(shí)放在表單的隱藏域里。接受處理表單數(shù)據(jù)時(shí),檢查標(biāo)識字串是否存在,并立即從session中刪除它,然后正常處理數(shù)據(jù)。

          如果發(fā)現(xiàn)表單提交里沒有有效的標(biāo)志串,這說明表單已經(jīng)被提交過了,忽略這次提交。

          這使你的web應(yīng)用有了更高級的XSRF保護(hù)。

          在數(shù)據(jù)庫里添加約束。在數(shù)據(jù)庫里添加唯一約束或創(chuàng)建唯一索引,防止出現(xiàn)重復(fù)數(shù)據(jù)。這是最有效的防止重復(fù)提交數(shù)據(jù)的方法。


          主站蜘蛛池模板: 无码国产精品一区二区免费vr| 搡老熟女老女人一区二区| 国产亚洲福利精品一区| 国产欧美一区二区精品仙草咪| 中文字幕久久亚洲一区| 国产精品无码一区二区三区毛片| 国产精品美女一区二区视频| 精品免费久久久久国产一区| 激情爆乳一区二区三区| 在线电影一区二区三区| 亚洲综合一区二区三区四区五区| 亚洲视频一区二区在线观看| 国产suv精品一区二区33| 久久精品无码一区二区app| 日韩有码一区二区| 国产一区韩国女主播| 在线观看国产一区二区三区| 精品爆乳一区二区三区无码av| 亚洲AV综合色区无码一区爱AV | 亚洲欧美日韩中文字幕在线一区| 国产av一区二区三区日韩 | 国产美女一区二区三区| 久久久无码一区二区三区| 日本一区二区三区在线观看| 国产精品视频第一区二区三区| 中文字幕日韩人妻不卡一区| 亚洲一区二区三区偷拍女厕 | 中文乱码精品一区二区三区| 国产av福利一区二区三巨| 在线视频一区二区三区三区不卡| 日本亚洲国产一区二区三区| 无码免费一区二区三区免费播放| 久久久精品人妻一区亚美研究所 | 不卡无码人妻一区三区音频| 国产精华液一区二区区别大吗| 无码人妻精品一区二区三区在线| 日本一区二区视频| 在线观看日韩一区| 国产午夜精品免费一区二区三区| 一区二区精品在线| 国产乱码精品一区二区三区麻豆 |