整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          如何快速學習 Java 系列之跨域(CORS)請求(

          如何快速學習 Java 系列之跨域(CORS)請求(day 5)

          天(第 4 天),我們實現了第一個 API —— echo,并通過 httpie 成功調用。今天我們來嘗試一下用瀏覽器來調用是否還能成功調通?答案是否定的。原因就是我們今天要學習的 瀏覽器同源策略 導致的,同時引出了 CORS 實現跨域訪問。本文主要內容包括:

          • CORS
          • 同源策略
          • 支持 CORS 跨域訪問
          • 預檢請求 Preflight Request



          瀏覽器調用 API 的嘗試

          先來回顧一下,在 day 4 文章的實例中,我們已經通過 httpie 成功的調用了 echo 接口,如下圖:

          非瀏覽器成功調用

          下面我們來寫個 JavaScript 腳本,通過瀏覽器來調用 echo 接口。


          • 直接運行 HTML 文件調用接口

          新建一個 html 文件,代碼如下:

          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
          </head>
          <body>
            <button onclick="callEcho()">call /api/util/echo</button>
            <script>
              function callEcho() {
                fetch('http://localhost:8991/api/util/echo', {
                  method: 'post',
                  headers: {
                    'Content-Type': 'application/json'
                  }, 
                  body: JSON.stringify({ name: 'zhangsan', num: 100 })
                })
                .then(res=> res.json())
                .then(res=> {
                  console.log(res)
                })
                .catch(err=> {
                  console.log(err)
                })
              }
            </script>
          </body>
          </html>

          保存后,雙擊用瀏覽器打開該 HTML,點擊按鈕即可觸發調用 echo 接口,調用結果如下:

          執行失敗,報被 CORS 策略阻塞


          • 通過 HTTP 服務器調用接口

          下面是 VUE 代碼,添加到 VUE 項目中,執行 yarn -dev 命令運行,點擊按鈕,觸發調用 echo 接口。

          <script setup>
            function callApiEcho() {
              fetch('http://localhost:8991/api/util/echo', {
                method: 'post',
                headers: {
                  'Content-Type': 'application/json'
                }, 
                body: JSON.stringify({ name: 'zhangsan', num: 100 })
              })
              .then(res=> res.json())
              .then(res=> {
                console.log(res)
              })
              .catch(err=> {
                console.log(err)
              })
            }
          </script>
          
          <template>
            <el-button type="primary" @click="callApiEcho">調用 /api/util/echo</el-button>
          </template>

          這種方式運行是有 HTTP 服務器的,調用的結果如下圖,它更清晰的指出了源域 IP

          執行失敗,報被 CORS 策略拒絕


          跨域(CORS)和同源策略(SOP)

          CORSCross Origin Resource Sharing, 俗稱“跨域”,全稱“跨域資源共享”,是每個 WEB 項目開發人員,不管是前端還是后端,都會遇到的問題。

          跨域問題是瀏覽器為了安全才有的,使用其它客戶端工具,比如 httpiecurl 等都沒有該問題。

          Web 瀏覽器實現了一種被稱為同源策略的安全機制,防止網頁在不同域中訪問資源,包括 API;而 CORS 提供了一種安全的方式,允許一個域(源域,用 origin 表示)調用另一個域中的資源,即允許在一個域下運行的 web 應用程序訪問另一個域。

          SOPSame Origin Policy同源策略同源是指協議、域名和端口都相同,任何一個不相同都不算同源


          跨域請求和響應

          CORS Request 有兩類:"simple" requests"preflight" requests,瀏覽器自己會決定使用哪種請求,無需我們人為的干預。我們需要了解該機制即可。

          • 簡單請求 Simple requests (GET, POST, HEAD)

          當請求滿足下面條件時,瀏覽器將該請求視為“simple”請求:

          (1)使用 GETPOST HEAD 請求

          (2)使用 CORS safe-listed header

          (3)使用 Content-Type header 值為 application/x-wwww-form-urlencodedmultipart/form-datatext/plain

          (4)沒有在任何 XMLHttpRequestUpload 對象上注冊事件偵聽器

          (5)請求中未使用 ReadableStream 對象

          滿足這些條件的請求,則被允許繼續正常執行,不會被阻止,并且在返回響應時檢查 Access-Control-Allow-Origin header

          • 預檢請求 Preflight requests (OPTIONS)

          如果不是“simple” request,瀏覽器將使用 HTTP OPTIONS 方法自動發出預檢請求預檢請求用于確定服務端確切的 CORS 能力,判斷服務端是否理解預期的 CORS 協議。 如果 OPTIONS 調用的結果指示無法請求,則不會再發起對服務端的實際請求

          預檢請求將請求模式設置為 OPTIONS,并設置一組 header 來描述接下來的請求:

          (1)Access-Control-Request-Method:請求的預期方法(如 GET、POST

          (2)Access-Control-Request-Headers:將隨請求一起發送的自定義 header 的名稱

          (3)Origincurrent origin

          預檢請求舉例:

          curl -i -X OPTIONS localhost:3031/api/echo \
          -H 'Access-Control-Request-Method: GET' \
          -H 'Access-Control-Request-Headers: Content-Type, Accept' \
          -H 'Origin: http://localhost:3030'

          這個例子表示,客戶端向服務端詢問:我想向從 http://localhost:3030 向 http://localhost:3031/api/echo 發起一個 Get 請求,該請求包含 “Content-Type, Acceptheader,是否可以?

          服務器判斷后,在響應中包含一些類似 Access-Control-*header,以指示是否允許隨后的請求。 這些 header 有如下幾種:

          (1)Access-Control-Allow-Origin: 表示允許發請求的源, “*” 表示允許所有源訪問

          (2)Access-Control-Allow-Methods: 允許的 HTTP methods,以逗號分隔

          (3)Access-Control-Allow-Headers: 允許發送的 custom headers,以逗號分隔

          (4)Access-Control-Max-Age: preflight request 預請求響應結果的緩存時長,在這段時長內,再次調用該接口不用進行預請求調用。

          一個 preflight 請求的 Response 可能是像下面這樣的:

          HTTP/1.1 204 No Content
          Access-Control-Allow-Origin: *
          Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
          Vary: Access-Control-Request-Headers
          Access-Control-Allow-Headers: Content-Type, Accept
          Content-Length: 0
          Date: Fri, 05 Apr 2023 11:41:08 GMT
          Connection: keep-alive

          看到這里,是不是已經明白為什么在瀏覽器調試工具“網絡”窗口中經常看到發出一次請求,有兩條 log 的原因了吧?

          一次調用顯示兩條 log

          對的,沒錯就是因為其中一條是預檢請求,另外一條才是真實請求


          后端跨域的實現

          • 添加跨域配置

          后端跨域配置

          添加 CorsConfig.java 文件,代碼如下。

          import org.springframework.context.annotation.Configuration;
          import org.springframework.web.servlet.config.annotation.CorsRegistry;
          import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
          
          @Configuration
          public class CorsConfig implements WebMvcConfigurer {
              @Override
              public void addCorsMappings(CorsRegistry registry) {
                  registry.addMapping("/**")
                          // When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header.
                          // To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
                          .allowedOrigins("*")
                          //.allowedOriginPatterns("*")
                          .allowedMethods("GET", "POST", "DELETE")
                          .allowedHeaders("*")
                          // restful api 是無狀態的,無需緩存 cookie 等信息
                          //.allowCredentials(true)
                          // Access-Control-Max-Age header 表明預檢請求響應的有效時間。在有效時間內,瀏覽器無須為同一請求再次發起預檢請求。
                          // 請注意,瀏覽器自身維護了一個最大有效時間,如果該首部字段的值超過了最大有效時間,將不會生效。
                          // 在預檢中,瀏覽器發送的頭中包含有 HTTP 方法和真實請求中會用到的頭。
                          // 也就是說對于同樣的請求,在 max-age 規定的時間內就不用再次通過預檢了,就可以直接請求了,單位s
                          .maxAge(1800);
              }
          }
          • 跨域調用

          支持跨域之后,我們再分別用 httpie 和 瀏覽器來調用 echo 接口看看有什變化。

          跨域前后 httpie 調用結果對比

          跨域前后 chrome 調用結果對比

          從上面實踐可以看到,支持跨域后,瀏覽器能成功調用 echo 接口了。


          預檢請求(Preflight Request)實戰

          最后我們再來增加一個 delete 接口,來親自見識一下“預檢請求”。

          從上面的解釋,我們知道預檢請求不能是 GETPOST 這種請求,而我們已有的 echo 接口是一個 POST 請求,所以需要新增一個符合條件的接口,這里我們增加一個 HTTP DELETE 接口來演示。

          增加 delete 接口

          • 添加接口

          增加一個新的 Controller,并添加 delete 接口,采用 @DeleteMapping 表示使用 HTTP DELETE 方法來請求。

          import com.example.springdemo.dto.ProductQueryDto;
          import com.example.springdemo.model.Result;
          import org.springframework.web.bind.annotation.*;
          
          @RestController
          @RequestMapping("api/product")
          public class ProductController {
              @DeleteMapping("delete")
              public Result<String> delete(@RequestBody ProductQueryDto param) {
                  System.out.printf("[product][del] %s\n", param.getId());
                  Result<String> res=new Result<>();
                  return res.setData(param.getId());
              }
          }

          增加 ProductQueryDto,用于接口傳參。這里大家先不用去管什么是 DTO,什么是 Model,后面的分享會逐一說明的。

          import lombok.Getter;
          import lombok.Setter;
          
          @Getter
          @Setter
          public class ProductQueryDto {
              private String id;
          }
          • 添加調用 delete 接口的 JavaScript 代碼
          <button onclick="callDeleteProduct()">call /api/product/delete</button>
            <script>
              function callDeleteProduct() {
                fetch('http://localhost:8991/api/product/delete', {
                  method: 'delete',
                  headers: {
                    'Content-Type': 'application/json'
                  }, 
                  body: JSON.stringify({ id: 'p001' })
                })
                .then(res=> res.json())
                .then(res=> {
                  console.log(res)
                })
                .catch(err=> {
                  console.log(err)
                })
              }
            </script>
          • 運行并調用 delete 接口

          一次調用,有兩條log

          點擊這兩條數據,查看兩次調用的請求頭和請求響應,對比如下圖:

          預檢請求和真正請求的對比

          小結,今天掌握了瀏覽器的同源策略 SOP,實現跨域訪問 CORS 的方法,學習了預檢請求 Preflight Request 和 Simple Request,自己定義了一個符合需要 Preflight Request 的接口,通過代碼親自做了實踐。

          這里是云端源想IT,幫你輕松學IT”

          嗨~ 今天的你過得還好嗎?

          我們總是先揚起塵土

          然后抱怨自己看不見

          - 2024.04.17 -

          JavaScript是一種輕量級的編程語言,通常用于網頁開發,以增強用戶界面的交互性和動態性。然而在HTML中,有多種方法可以嵌入和使用JavaScript代碼。

          本文就帶大家深入了解如何在HTML中使用JavaScript。



          一、使用 script 標簽

          要在HTML中使用JavaScript,我們需要使用<script>標簽。這個標簽可以放在<head>或<body>部分,但通常我們會將其放在<body>部分的底部,以確保在執行JavaScript代碼時,HTML文檔已經完全加載。

          使用 <script> 標簽有兩種方式:直接在頁面中嵌入 JavaScript 代碼包含外部 JavaScript 文件。


          包含在 <script> 標簽內的 JavaScript 代碼在瀏覽器總按照從上至下的順序依次解釋。


          所有 <script> 標簽都會按照他們在 HTML 中出現的先后順序依次被解析。



          HTML 為 <script> 定義了幾個屬性:

          1)async:可選。表示應該立即下載腳本,但不妨礙頁面中其他操作。該功能只對外部 JavaScript 文件有效。


          如果給一個外部引入的js文件設置了這個屬性,那頁面在解析代碼的時候遇到這個<script>的時候,一邊下載該腳本文件,一邊異步加載頁面其他內容。


          2)defer:可選。表示腳本可以延遲到整個頁面完全被解析和顯示之后再執行。該屬性只對外部 JavaScript 文件有效。


          3)src:可選。表示包含要執行代碼的外部文件。


          4)type:可選。表示編寫代碼使用的腳本語言的內容類型,目前在客戶端,type 屬性值一般使用 text/javascript。不過這個屬性并不是必需的,如果沒有指定這個屬性,則其默認值仍為text/javascript。



          1.1 直接在頁面中嵌入JavaScript代碼

          內部JavaScript是將JavaScript代碼放在HTML文檔的<script>標簽中。這樣可以將JavaScript代碼與HTML代碼分離,使結構更清晰,易于維護。


          在使用<script>元素嵌入JavaScript代碼時,只須為<script>指定type屬性。然后,像下面這樣把JavaScript代碼直接放在元素內部即可:

          <script type="text/javascript">
          function sayHi(){
          alert("Hi!");
          }
          </script>


          如果沒有指定script屬性,則其默認值為text/javascript。


          包含在<script>元素內部的JavaScript代碼將被從上至下依次解釋。在解釋器對<script>元素內部的所有代碼求值完畢以前,頁面中的其余內容都不會被瀏覽器加載或顯示。


          在使用<script>嵌入JavaScript代碼的過程中,當代碼中出現"</script>"字符串時,由于解析嵌入式代碼的規則,瀏覽器會認為這是結束的</script>標簽。可以通過轉義字符“\”寫成<\/script>來解決這個問題。


          1.2 包含外部 JavaScript 文件

          外部JavaScript是將JavaScript代碼放在單獨的.js文件中,然后在HTML文檔中通過<script>標簽的src屬性引用這個文件。這種方法可以使代碼更加模塊化,便于重用和共享。


          如果要通過<script>元素來包含外部JavaScript文件,那么src屬性就是必需的。這個屬性的值是一個指向外部JavaScript文件的鏈接。

          <script type="text/javascript" src="example.js"></script>


          • 外部文件example.js將被加載到當前頁面中。
          • 外部文件只須包含通常要放在開始的<script>和結束的</script>之間的那些JavaScript代碼即可。



          與解析嵌入式JavaScript代碼一樣,在解析外部JavaScript文件(包括下載該文件)時,頁面的處理也會暫時停止。

          注意:帶有src屬性的<script>元素不應該在其<script>和</script>標簽之間再包含額外的JavaScript代碼。如果包含了嵌入的代碼,則只會下載并執行外部腳本文件,嵌入的代碼會被忽略。

          通過<script>元素的src屬性還可以包含來自外部域的JavaScript文件。它的src屬性可以是指向當前HTML頁面所在域之外的某個域中的完整URL。

          <script type="text/javascript" src="http://www.somewhere.com/afile.js"></script>

          于是,位于外部域中的代碼也會被加載和解析。


          1.3 標簽的位置

          在HTML中,所有的<script>標簽會按照它們出現的先后順序被解析。在不使用defer和async屬性的情況下,只有當前面的<script>標簽中的代碼解析完成后,才會開始解析后面的<script>標簽中的代碼。


          通常,所有的<script>標簽應該放在頁面的<head>標簽中,這樣可以將外部文件(包括CSS和JavaScript文件)的引用集中放置。



          然而,如果將所有的JavaScript文件都放在<head>標簽中,會導致瀏覽器在呈現頁面內容之前必須下載、解析并執行所有JavaScript代碼,這可能會造成明顯的延遲,導致瀏覽器窗口在加載過程中出現空白。


          為了避免這種延遲問題,現代Web應用程序通常會將所有的JavaScript引用放置在<body>標簽中的頁面內容的后面。這樣做可以確保在解析JavaScript代碼之前,頁面的內容已經完全呈現在瀏覽器中,從而加快了打開網頁的速度。


          二、執行JavaScript 程序

          JavaScript 解析過程包括兩個階段:預處理(也稱預編譯)執行

          • 在編譯期,JavaScript 解析器將完成對 JavaScript 代碼的預處理操作,把 JavaScript 代碼轉換成字節碼;
          • 在執行期,JavaScript 解析器把字節碼生成二進制機械碼,并按順序執行,完成程序設計的任務。


          1、執行過程

          HTML 文檔在瀏覽器中的解析過程是:按照文檔流從上到下逐步解析頁面結構和信息。

          JavaScript 代碼作為嵌入的腳本應該也算做 HTML 文檔的組成部分,所以 JavaScript 代碼在裝載時的執行順序也是根據 <script> 標簽出現的順序來確定。

          你是不是厭倦了一成不變的編程模式?想要突破自我,挑戰新技術想要突破自我,挑戰新技術?卻遲遲找不到可以練手的項目實戰?是不是夢想打造一個屬于自己的支付系統?那么,恭喜你,云端源想免費實戰直播——《微實戰-使用支付寶/微信支付服務,網站在線支付功能大揭秘》正在進行,點擊前往獲取源碼!云端源想

          2、預編譯

          當 JavaScript 引擎解析腳本時候,他會在與編譯期對所有聲明的變量和函數預先進行處理。當 JavaScript 解析器執行下面腳本時不會報錯。

          alert(a); //返回值 undefined
          var a=1;
          alert(a); //返回值 1


          由于變量聲明是在預編譯期被處理的,在執行期間對于所有的代碼來說,都是可見的,但是執行上面代碼,提示的值是 undefined 而不是 1。

          因為變量初始化過程發生在執行期,而不是預編譯期。在執行期,JavaScript 解析器是按照代碼先后順序進行解析的,如果在前面代碼行中沒有為變量賦值,則 JavaScript 解析器會使用默認值 undefined 。


          由于第二行中為變量 a 賦值了,所以在第三行代碼中會提示變量 a 的值為 1,而不是 undefined。

          fun(); //調用函數,返回值1
          function fun(){
          alert(1);
          }

          函數聲明前調用函數也是合法的,并能夠正確解析,所以返回值是 1。但如果是下面這種方式則 JavaScript 解釋器會報錯。

          fun(); //調用函數,返回語法錯誤
          var fun=function(){
          alert(1);
          }

          上面的這個例子中定義的函數僅作為值賦值給變量 fun 。在預編譯期,JavaScript 解釋器只能夠為聲明變量 fun 進行處理,而對于變量 fun 的值,只能等到執行期時按照順序進行賦值,自然就會出現語法錯誤,提示找不到對象 fun。

          總結:聲明變量和函數可以在文檔的任意位置,但是良好的習慣應該是在所有 JavaScript 代碼之前聲明全局變量和函數,并對變量進行初始化賦值。在函數內部也是先聲明變量,后引用。

          通過今天的分享,相信大家已經對JavaScript在HTML中的應用有了一定的了解。這只是冰山一角,JavaScript的潛力遠不止于此。希望這篇文章能激發大家對編程的熱情,讓我們一起在編程的世界里探索更多的可能性!



          我們下期再見!


          END

          文案編輯|云端學長

          文案配圖|云端學長

          內容由:云端源想分享

          TML: HyperText Markup Language 超文本標記語言

          HTML代碼不區分大小寫, 包括HTML標記、屬性、屬性值都不區分大小寫;

          任何空格或回車鍵在代碼中都無效,插入空格或回車有專用的標記,分別是 、<br>

          HTML標記中不要有空格,否則瀏覽器可能無法識別。

          如何添加注釋(comment:評論;注釋)

          <!-- -->
          <comment></comment>
          <!-- --> 不能留有空格


          字符集

          <meta http-equiv="Content-Type" content="text/html;charset=#"/>


          <base target="_blank">

          可以將a鏈接的默認屬性設置為_blank屬性

          單個標簽要有最好有結束符(可以沒有結束符)

          <br/> <img src="" width="" /> 

          便于兼容XHTML(XHTML必須要有結束符)

          HTML標簽的屬性值可以有引號,可以沒有引號,為了提高代碼的可讀性,推薦使用引號(單引號和雙引號),盡管屬性值是整數,也推薦加上引號。

          <marquee behavior="slide"></marquee> 

          便于兼容XHTML(XHTML必須要有引號)

          <marquee behavior=slide></marquee>

          經過測試,以上程序都可以正確運行


          HTML標簽涉及到的顏色值格式:

          color_name 規定顏色值為顏色名稱的文本顏色(比如 "red")。

          hex_number 規定顏色值為十六進制值的文本顏色(比如 "#ff0000")。

          rgb_number 規定顏色值為 rgb 代碼的文本顏色(比如 "rgb(255,0,0)")。

          transparent 透明色 color:transparent

          rgba(紅0-255,綠0-255,藍0-255,透明度0-1)

          opacity屬性: 就是葫蘆娃兄弟老六(技能包隱身)

          css:

          div{opacity:0.1} /*取值為0-1*/

          英文(顏色值)不區分大小寫

          HTML中顏色值:采用十六進制兼容性最好(十六進制顯示顏色效果最佳)

          CSS中顏色值:不存在兼容性

          紅色 #FF0000

          綠色 #00FF00

          藍色 #0000FF

          黑色: #000000

          灰色 #CCCCCC

          白色 #FFFFFF

          青色 #00FFFF

          洋紅 #FF00FF

          黃色 #FFFF00


          請問后綴 html 和 htm 有什么區別?

          答: 1. 如果一個網站有 index.html和index.htm,默認情況下,優先訪問.html

          2. htm后綴是為了兼容以前的DOS系統8.3的命名規范

          XHTML與HTML之間的關系?

          XHTML是EXtensible HyperText Markup Language的英文縮寫,即可擴展的超文本標記語言.

          XHTML語言是一種標記語言,它不需要編譯,可以直接由瀏覽器執行.

          XHTML是用來代替HTML的, 是2000年w3c公布發行的.

          XHTML是一種增強了的HTML,它的可擴展性和靈活性將適應未來網絡應用更多的需求.

          XHTML是基于XML的應用.

          XHTML更簡潔更嚴謹.

          XHTML也可以說就是HTML一個升級版本.(w3c描述它為'HTML 4.01')

          XHTML是大小寫敏感的,XHTML與HTML是不一樣的;HTML不區分大小寫,標準的XHTML標簽應該使用小寫.

          XHTML屬性值必須使用引號,而HTML屬性值可用引號,可不要引號

          XHTML屬性不能簡寫:如checked必須寫成checked="checked"

          單標記<br>, XHTML必須有結束符<br/>,而HTML可以使用<br>,也可以使用<br/>

          除此之外XHTML和HTML基本相同.


          網頁寬度設置多少為最佳?

          960px


          target屬性值理解

          _self 在當前窗口中打開鏈接文件,是默認值

          _blank 開啟一個新的窗口打開鏈接文件

          _parent 在父級窗口中打開文件,常用于框架頁面

          _top 在頂層窗口中打開文件,常用語框架頁面


          字符集:

          charset=utf-8

          Gb2312 簡單中文字符集, 最常用的中文字符

          Gbk 簡繁體字符集, 中文字符集

          Big5 繁體字符集, 臺灣等等

          Utf-8 世界性語言的字符集

          ANSI編碼格式編碼格式的擴展字符集有gb2312和gbk

          單位問題:

          HTML屬性值數值型的一般不帶單位, CSS必須帶單位;


          強制刷新

          ctrl+F5


          主站蜘蛛池模板: 人妻无码一区二区三区AV| 成人免费一区二区三区在线观看| 久久99精品波多结衣一区| 亚洲欧美成人一区二区三区| 红杏亚洲影院一区二区三区| 国产一区二区三区樱花动漫| 亚洲一区动漫卡通在线播放| 亚洲一区二区三区影院| 欧洲精品一区二区三区在线观看| 午夜视频一区二区| 欧美日韩精品一区二区在线视频| 亚洲电影唐人社一区二区| 无码人妻精品一区二区| 久久人妻av一区二区软件| 中文人妻无码一区二区三区| 97精品国产福利一区二区三区| 国产一区二区三区不卡在线观看| 国产精品一区在线麻豆| 中文字幕无码不卡一区二区三区| 久久精品无码一区二区无码| 亚洲成在人天堂一区二区| 色偷偷一区二区无码视频| 一区二区三区精品| 亚洲制服丝袜一区二区三区| 亚洲av无码片区一区二区三区| 日韩精品无码一区二区三区免费| 国产一区二区三区久久| 日本成人一区二区| 亚洲福利秒拍一区二区| 日日摸夜夜添一区| 精品日韩一区二区| 一区二区三区电影网| 中文字幕一区二区区免| 国产在线一区二区| 久久er99热精品一区二区| AV无码精品一区二区三区| 激情综合丝袜美女一区二区 | 色一情一乱一区二区三区啪啪高 | 久久99久久无码毛片一区二区| 一级特黄性色生活片一区二区 | 欧美亚洲精品一区二区|