整合營銷服務商

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

          免費咨詢熱線:

          Go 語言 Web 編程系列-獲取用戶請求數據(上)

          Go 語言 Web 編程系列-獲取用戶請求數據(上)

          、GET/POST 請求數據

          在 PHP 中,可以直接通過全局變量 $_GET 和 $_POST 快速獲取 GET/POST 請求數據,GET 請求數據主要是 URL 查詢字符串中包含的參數,以前面在線論壇項目的群組詳情頁為例:

          http://localhost:8080/thread/read?id=adb02107-d7c3-4f27-4de4-b586f231380e

          上述 URL 請求中的 id=adb02107-d7c3-4f27-4de4-b586f231380e 就屬于 GET 請求數據,也就是查詢字符串,而對于用戶登錄表單:

          當用戶輸入注冊郵箱和密碼后點擊「登錄」按鈕,會將輸入框中的數據作為請求實體發送 POST 請求到服務端,執行登錄認證,這里的表單數據就是 POST 請求數據,如果我們查看表單請求路由的 HTTP 報文:

          就會看到表單請求數據,也就是上文提到的 HTTP 請求實體。

          當然根據對服務端資源的操作類型不同,可以進一步細分為 POST、PUT、PATCH、DELETE 等包含請求實體的請求方法,為了簡化模型,我們這里只討論 POST 請求,而且其他幾種請求方法也可以統一通過 POST 請求完成,通常只有在設計遵循 RESTful 風格的 API 接口時,才會嚴格劃分不同的請求方法,關于這一點,后面介紹 REST + JSON 接口時再詳細討論。

          1、Form

          Go 語言中獲取用戶請求數據的方式要更復雜一些,Go 也為此提供多個不同的結構體幫助我們讀取不同請求類型的數據,首先,我們可以通過請求對象上的 Form 讀取所有 GET/POST 請求數據,在 handlers/post.go 中新增 EditPost 方法如下:

          func EditPost(w http.ResponseWriter, r *http.Request)  {
              r.ParseForm()
              fmt.Fprintln(w, r.Form)
          }

          需要注意的是,在通過 r.Form 獲取所有請求數據之前,必須要先通過 r.ParseForm() 解析所有請求數據,否則無法獲取數據。

          在 routes/web.go 中新增一個路由:

          WebRoute{
              "UpdatePost",
              "POST",
              "/post/edit",
              handlers.EditPost,
          },

          然后我們重啟 HTTP 服務器,在命令行通過 curl 發起一個包含不同類型請求數據的請求:

          可以看到,打印結果表明 r.Form 是一個包含所有請求數據的字典類型(map),包含 URL 查詢字符串和 POST 請求數據,這是一個 POST 請求,如果是 GET 請求呢?我們為 EditPost定義一個 GET 請求路由:

          WebRoute{
              "EditPost",
              "GET",
              "/post/edit",
              handlers.EditPost,
          },

          再重啟 HTTP 服務器,發起一個只包含查詢字符串的 GET 請求(默認是 GET 請求,不需要通過 -X GET 指定):

          同樣可以打印出和 POST 請求完全一樣的結果。

          因此,request 對象上的 Form 可以獲取所有請求參數,包括查詢字符串和請求實體,并且不限請求類型。如果你想要進一步要獲取指定的參數值,可以以索引方式獲取指定參數對應的值,也可以通過 Form 提供的 Get 方法,就像我們從一個普通字典類型獲取鍵值一樣:

          id1 := r.Form["id"]
          id2 := r.Form.Get("id")
          fmt.Println(id1)
          fmt.Println(id2)

          只不過兩者的返回值類型不一樣,前者是一個字符串切片,后者是一個字符串值:

          [1]
          1

          2、PostForm

          上面的結果同時返回了查詢字符串和請求實體,如果只想獲取請求實體(即 POST 表單中的數據),可以通過 PostForm 實現:

          func EditPost(w http.ResponseWriter, r *http.Request)  {
              r.ParseForm()
              id := r.Form.Get("id")
              fmt.Println("post id:", id)
              fmt.Println("form data:", r.PostForm)
              io.WriteString(w, "表單提交成功")
          }

          這樣一來,就只能獲取到 POST 數據了:

          然后在 HTTP 服務器日志,可以看到如下答應結果:

          可以看到 r.PostForm 返回的也是字典類型數據,數據格式和 r.Form 完全一致,并且這次只包含了 POST 表單請求數據,不包含 URL 查詢字符串,也就是說,通過 r.PostForm 只能獲取 POST 請求數據(請求實體數據),無法獲取 GET 請求數據(查詢字符串中的數據),你可以再次發起 GET 請求進行驗證:

          這個時候,可以看到服務器打印日志之包含 id 信息,表單信息為空:

          通過 PostForm 獲取具體參數值的方式和 Form 一樣,這里就不再贅述了:

          title := r.PostForm.Get("title")
          content := r.PostForm.Get("content")

          實際上,我們在前面的在線論壇項目中,就是通過這個方式獲取表單請求數據的:

          err := request.ParseForm()
          user, err := models.UserByEmail(request.PostFormValue("email"))

          3、FormValue/PostFormValue

          最后,還可以通過 FormValue 和 PostFormValue 獲取用戶請求數據,使用它們的好處是不再需要單獨調用 ParseForm 對表單數據進行解析,不過使用這兩個方法的時候只能獲取特定請求數據,不能一次獲取所有請求數據:

          func EditPost(w http.ResponseWriter, r *http.Request)  {
              fmt.Println("post id:", r.FormValue("id"))
              fmt.Println("post title:", r.PostFormValue("title"))
              fmt.Println("post title:", r.PostFormValue("content"))
              io.WriteString(w, "表單提交成功")
          }

          FormValue/PostFormValue 的區別和 Form/PostForm 一樣,這里通過命名就可以看出來,前者可以獲取所有 GET/POST 請求數據(即查詢字符串和請求實體),后者只能獲取 POST 請求實體數據。

          注:FormValue/PostFormValue 之所以不用顯式調用 ParseForm 解析請求數據,是因為底層對其進行了封裝,實際上還是要調用這個方法。

          4、獲取 JSON 請求數據

          上面的示例默認都是基于 HTML 表單請求,對于客戶端提交的 JSON 格式數據,使用ParseForm 是無法解析并獲取數據的,因為 HTML 表單請求數據默認是通過 application/x-www-form-urlencoded 編碼的,而 JSON 請求數據通常是通過 application/json 編碼,ParseForm 只能解析通過 application/x-www-form-urlencoded 編碼的數據。

          對于 JSON 請求數據的解析,目前我們可以通過上篇教程介紹的,讀取完整請求實體并進行 JSON 解碼實現,下面我們改寫 AddPost 方法實現如下:

          type Post struct {
              Title string `json:"title"`
              Content string `json:"content"`
          }
          
          func AddPost(w http.ResponseWriter, r *http.Request)  {
              len := r.ContentLength   // 獲取請求實體長度
              body := make([]byte, len)  // 創建存放請求實體的字節切片
              r.Body.Read(body)        // 調用 Read 方法讀取請求實體并將返回內容存放到上面創建的字節切片
              // io.WriteString(w, string(body))
              post := Post{}
              json.Unmarshal(body, &post)  // 對讀取的 JSON 數據進行解析
              fmt.Fprintf(w, "%#v\n", post)   // 格式化輸出結果
          }

          我們將讀取的請求實體數據通過 JSON 解碼映射到 Post 結構體對象并將其輸出到響應結果。

          重啟 HTTP 服務器,通過 curl 模擬客戶端提交 JSON 請求數據:

          我們通過 -H 選項指定請求數據編碼格式為 application/json,然后請求數據調整為 JSON 格式字符串,最后通過輸出結果可以看到在服務端 JSON 請求數據已經可以成功解析并獲取。

          5、小結

          到這里,我們已經了解了在 Go Web 編程中,常見的用戶請求數據如何解析并獲取(URL 查詢字符串、POST 表單數據、JSON 請求數據),實際上,和 PHP 中的 $_GET 和 $_POST 類似,Go 也是將 HTTP 請求數據映射到請求對象對應的結構體,然后開發者可以從上下文請求對象中解析并讀取這些請求數據,使用這些封裝好的對象的好處是它們屏蔽了底層的細節,統一了數據格式,可以大大提高開發效率,減少不必要的數據格式兼容成本。

          下篇教程,學院君將給大家介紹如何從表單請求中獲取文件數據,并實現簡單的文件上傳功能。

          (全文完)

          單是PHP程序中最常使用的收集站點訪問者信息的數據輸入界面。通過表單瀏覽器獲取用戶的輸入數據,并傳送給Web服務器的腳本程序中,以各種不同的方式進行處理。在表單中提供了多種輸入方式,包括文本輸入域、單選或多選按鈕、下拉式列表域等。表單是網頁上由<form>標簽定義的一個特定區域,而表單的各種輸入域可以由<input>、<select>和<textarea> 3個標簽定義。

          1 表單標簽<form>

          一個表單用<form></form>標簽來創建,即定義表單的開始和結束位置,在開始和結束標簽之間的一切定義都屬于表單的內容。單擊提交按鈕時,提交的也是表單范圍之內的內容。另外,在<form>標簽中需要攜帶表單的相關信息,例如處理表單的腳本程序的位置、提交表單的方法等。這些信息對于瀏覽者是不可見的,但對于處理表單卻有著決定性的作用。該標簽的常用屬性如表1所示。

          表1 HTML表單標簽中常用的屬性


          <form>標簽中必須加action屬性,并且不能為空。例如,<form action="login.php" method="post">。如果不需要使用action屬性,也必須定義:<form action="no">。

          2 文本域和密碼域

          在<form>標簽內定義的<input>標簽具有重要的地位,該標簽是單個標簽,沒有結束標記。<input type="">標簽用來定義一個用戶輸入區,用戶可以在其中輸入信息。<input>標簽中共提供了9種類型的輸入區域,具體是哪一種類型由type屬性來決定。文本和密碼輸入域是一個單行文本框,它們基本相似,唯一不同的是,用戶在密碼域中輸入的字符并不以原樣顯示,而是將每個字符用“*”代替。文本和密碼輸入域的基本語法格式如下:

          <input type="text" name="field_name" value="field_value" size="n" maxlength="n"> <!-- 輸入域 -->

          <input type="password" name="field_name" value="field_value" size="n" maxlength="n"> <!-- 密碼域 -->

          這些屬性的含義如表2所示。

          表2 HTML中<input>標簽的常用屬性z

          3 提交、重置和普通按鈕

          在<input>標簽中,當type屬性值為“submit”時,表示這是一個提交按鈕,單擊提交按鈕后,可以實現表單內容的提交;當type屬性為“reset”時,表示這是一個重置按鈕,單擊重置按鈕后,表單的內容將恢復為默認值;當type屬性為“button”時,表示這是一個普通按鈕,并不實現任何功能,需要和JavaScript等腳本語言一起使用。button按鈕必須定義在form之間,否則Netscape瀏覽器不支持。這3種按鈕的基本語法格式如下:

          <input type="submit" name="field_name" value="field_value"> <!-- 提交按鈕 -->

          <input type="reset" name="field_name" value="field_value"> <!-- 重置按鈕 -->

          <input type="button" name="field_name" value="field_value"> <!-- 普通按鈕 -->

          4 單選按鈕和復選框

          單選按鈕和復選框都有“選中”和“未選中”兩種狀態。同一組單選按鈕如果有多個選擇框,則選擇框之間是相互排斥的,只允許用戶選擇其中的一個。復選框和單選按鈕的區別是,復選框允許用戶同時選中同一表單中的多個或全部選項,當然,也可以只選其中的一個選項。它們都是只有在“選中”時,數據才能被提交到服務器端。其語法格式如下所示:

          <input type="radio" name="field_name" value="field_value" checked> <!-- 單選按鈕 -->

          <input type="checkbox" name="field_name" value="field_value" checked> <!-- 復選框 -->

          在<input>標簽中,當type屬性值為“checkbox”時,表示這是一個復選框輸入域;當type屬性值為“radio”時,則表示這是一個單選按鈕輸入域。但在同一組中的多個單選按鈕名稱必須相同,它們之間才能相互排斥。單選按鈕和復選框都可以通過checked屬性設置為選中狀態。

          .引用相關頭文件

          引入CSS:

          <link href="Scripts/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css" />

          <link href="Scripts/ui.jqgrid.css" rel="stylesheet" type="text/css" />

          引入JS:

          <script src="Scripts/jquery-1.5.1.js" type="text/javascript"></script>

          <script src="Scripts/jquery-ui.min.js" type="text/javascript"></script>

          <script src="Scripts/grid.locale-en.js" type="text/javascript"></script>

          <script src="Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

          因為jqGrid3.6及以后的版本集成了jQuery UI,所以,此處需要導入UI相關js和css。另外grid.locale-en.js這個語言文件必須在jquery.jqGrid.min.js之前加載,否則會出問題。

          2.將jqgrid加入頁面中

          根據jqGrid的文檔,要想生成一個jqGrid,最直接的方法就是:

          $("#list").jqGrid(options);

          其中list是頁面上的一個table:<table id="list"></table>

          下面是一個簡單的例子:

          <script type="text/javascript">

          $(document).ready(function () {

          jQuery("#list").jqGrid({

          url: 'Handler.ashx',

          datatype: "json",

          mtype: 'GET',

          colNames: ['SalesReasonID', 'Name', 'ReasonType', 'ModifiedDate'],

          colModel: [

          { name: 'SalesReasonID', index: 'SalesReasonID', width: 40, align: "left", editable: true },

          { name: 'Name', index: 'Name', width: 100, align: "center" },

          { name: 'ReasonType', index: 'ReasonType', width: 100, align: "center" },

          { name: 'ModifiedDate', index: 'ModifiedDate', width: 150, align: "center", search: false }

          ],

          rowList: [10, 20, 30],

          sortname: 'SalesReasonID',

          viewrecords: true,

          sortorder: "desc",

          jsonReader: {

          root: "griddata",

          total: "totalpages",

          page: "currpage",

          records: "totalrecords",

          repeatitems: false

          },

          pager: jQuery('#pager'),

          rowNum: 5,

          altclass: 'altRowsColour',

          //width: 'auto',

          width: '500',

          height: 'auto',

          caption: "DemoGrid"

          }).navGrid('#pager', { add: true, edit: true, del: true,search:false,refresh:false }); ;

          })

          二、 jqgrid的重要選項

          具體的options參考,可以訪問jqGrid文檔關于option的章節(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options)。其中有幾個是比較常用的,重點介紹一下:

          • url :jqGrid控件通過這個參數得到需要顯示的數據,具體的返回值可以使XML也可以是Json。
          • datatype :這個參數用于設定將要得到的數據類型。類型包括:json 、xml、xmlstring、local、javascript、function。
          • mtype : 定義使用哪種方法發起請求,GET或者POST。
          • height :Grid的高度,可以接受數字、%值、auto,默認值為150。
          • width :Grid的寬度,如果未設置,則寬度應為所有列寬的之和;如果設置了寬度,則每列的寬度將會根據shrinkToFit選項的設置,進行設置。
          • shrinkToFit :此選項用于根據width計算每列寬度的算法。默認值為true。如果shrinkToFit為true且設置了width值,則每列寬度會根據width成比例縮放;如果shrinkToFit為false且設置了width值,則每列的寬度不會成比例縮放,而是保持原有設置,而Grid將會有水平滾動條。
          • autowidth :默認值為false。如果設為true,則Grid的寬度會根據父容器的寬度自動重算。重算僅發生在Grid初始化的階段;如果當父容器尺寸變化了,同時也需要變化Grid的尺寸的話,則需要在自己的代碼中調用setGridWidth方法來完成。
          • pager :定義頁碼控制條Page Bar,在上面的例子中是用一個div(<div id=”pager”></div>)來放置的。
          • sortname :指定默認的排序列,可以是列名也可以是數字。此參數會在被傳遞到Server端。
          • viewrecords :設置是否在Pager Bar顯示所有記錄的總數。
          • caption :設置Grid表格的標題,如果未設置,則標題區域不顯示。
          • rowNum :用于設置Grid中一次顯示的行數,默認值為20。正是這個選項將參數rows(prmNames中設置的)通過url選項設置的鏈接傳遞到Server。注意如果Server返回的數據行數超過了rowNum的設定,則Grid也只顯示rowNum設定的行數。
          • rowList :一個數組,用于設置Grid可以接受的rowNum值。例如[10,20,30]。
          • colNames :字符串數組,用于指定各列的題頭文本,與列的順序是對應的。
          • colModel :最重要的數組之一,用于設定各列的參數。(稍后詳述)
          • prmNames :這是一個數組,用于設置jqGrid將要向Server傳遞的參數名稱。(稍后詳述)
          • jsonReader :這又是一個數組,用來設定如何解析從Server端發回來的json數據。(稍后詳述)

          2.1 prmNames選項

          prmNames是jqGrid的一個重要選項,用于設置jqGrid將要向Server傳遞的參數名稱。其默認值為:

          prmNames : {

          page:"page", // 表示請求頁碼的參數名稱

          rows:"rows", // 表示請求行數的參數名稱

          sort: "sidx", // 表示用于排序的列名的參數名稱

          order: "sord", // 表示采用的排序方式的參數名稱

          search:"_search", // 表示是否是搜索請求的參數名稱

          nd:"nd", // 表示已經發送請求的次數的參數名稱

          id:"id", // 表示當在編輯數據模塊中發送數據時,使用的id的名稱

          oper:"oper", // operation參數名稱

          editoper:"edit", // 當在edit模式中提交數據時,操作的名稱

          addoper:"add", // 當在add模式中提交數據時,操作的名稱

          deloper:"del", // 當在delete模式中提交數據時,操作的名稱

          subgridid:"id", // 當點擊以載入數據到子表時,傳遞的數據名稱

          npage: null,

          totalrows:"totalrows" // 表示需從Server得到總共多少行數據的參數名稱,參見jqGrid選項中的rowTotal

          }

          2.2 jsonReader選項

          jsonReader是jqGrid的一個重要選項,用于設置如何解析從Server端發回來的json數據,如果Server返回的是xml數據,則對應的使用xmlReader來解析。jsonReader的默認值為:

          jsonReader : {

          root: "rows", // json中代表實際模型數據的入口

          page: "page", // json中代表當前頁碼的數據

          total: "total", // json中代表頁碼總數的數據

          records: "records", // json中代表數據行總數的數據

          repeatitems: true, // 如果設為false,則jqGrid在解析json時,會根據name來搜索對應的數據元素(即可以json中元素可以不按順序);而所使用的name是來自于colModel中的name設定。

          cell: "cell",

          id: "id",

          userdata: "userdata",

          subgrid: {

          root:"rows",

          repeatitems: true,

          cell:"cell"

          }

          }

          假如有下面一個json字符串:

          {"totalpages":"3","currpage":"1","totalrecords":"11","griddata":[{"SalesReasonID":"1","Name":"Price","ReasonType":"Other","ModifiedDate":"1998年6月1日"},{"SalesReasonID":"2","Name":"On Promotion","ReasonType":"Promotion","ModifiedDate":"1998年6月1日"},{"SalesReasonID":"3","Name":"Magazine Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"},{"SalesReasonID":"4","Name":"Television Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"},{"SalesReasonID":"5","Name":"Manufacturer","ReasonType":"Other","ModifiedDate":"1998年6月1日"}]}

          其對應的jsonReader為:jsonReader: {

          root: "griddata",

          total: "totalpages",

          page: "currpage",

          records: "totalrecords",

          repeatitems: false

          }

          注:cell、id在repeatitems為true時可以用到,即每一個記錄是由一對id和cell組合而成,即可以適用另一種json結構。援引文檔中的例子:

          repeatitems為true時:

          jQuery("#gridid").jqGrid({

          ...

          jsonReader : {

          root:"invdata",

          page: "currpage",

          total: "totalpages",

          records: "totalrecords"

          },

          ...

          });

          json結構為:

          {

          "totalpages": "xxx",

          "currpage": "yyy",

          "totalrecords": "zzz",

          "invdata" : [

          {"id" :"1", "cell" :["cell11", "cell12", "cell13"]}, // cell中不需要各列的name,只要值就OK了,但是需要保持對應

          {"id" :"2", "cell" :["cell21", "cell22", "cell23"]},

          ...

          ]

          }

          repeatitems為false時:

          jQuery("#gridid").jqGrid({

          ...

          jsonReader : {

          root:"invdata",

          page: "currpage",

          total: "totalpages",

          records: "totalrecords",

          repeatitems: false,

          id: "0"

          },

          ...

          });

          json結構為:

          {

          "totalpages" : "xxx",

          "currpage" : "yyy",

          "totalrecords" : "zzz",

          "invdata" : [

          {"invid" : "1","invdate":"cell11", "amount" :"cell12", "tax" :"cell13", "total" :"1234", "note" :"somenote"}, // 數據中需要各列的name,但是可以不按列的順序

          {"invid" : "2","invdate":"cell21", "amount" :"cell22", "tax" :"cell23", "total" :"2345", "note" :"some note"},

          ...

          ]

          }

          2.3 colModel的重要選項

          colModel也有許多非常重要的選項,在使用搜索、排序等方面都會用到。這里先只說說最基本的。

          • name :為Grid中的每個列設置唯一的名稱,這是一個必需選項,其中保留字包括subgrid、cb、rn。
          • index :設置排序時所使用的索引名稱,這個index名稱會作為sidx參數(prmNames中設置的)傳遞到Server。
          • label :當jqGrid的colNames選項數組為空時,為各列指定題頭。如果colNames和此項都為空時,則name選項值會成為題頭。
          • width :設置列的寬度,目前只能接受以px為單位的數值,默認為150。
          • sortable :設置該列是否可以排序,默認為true。
          • search :設置該列是否可以被列為搜索條件,默認為true。
          • resizable :設置列是否可以變更尺寸,默認為true。
          • hidden :設置此列初始化時是否為隱藏狀態,默認為false。
          • formatter :預設類型或用來格式化該列的自定義函數名。常用預設格式有:integer、date、currency、number等(具體參見文檔 )。

          三、 注意事項

          1. 動態改變Add Form或者Edit Form中的select的內容,如:改變下圖中的Comparator下拉中的內容。

          $("#list_d").navGrid('#pager_d',{add:true,edit:true,del:true,search:false,refresh:false},

          {

          checkOnSubmit:false, closeAfterEdit: true,recreateForm:true,

          beforeInitData:function(formid){

          initComparator();

          },

          beforeShowForm: function(formid){

          $("#list_d").jqGrid('setColProp', 'Name', { editrules:{required:false},});

          $('#tr_Name', formid).hide();

          }

          },//edit

          {},//add

          {}//del

          beforeInitData, beforeShowForm在每次點擊編輯的時候都會執行。initComparator的作用是通過ajax獲取數據,然后利用$("#list_d").jqGrid('setColProp', 'Comparator', { editoptions: { value: valueString} });來設置Comparator下拉中的內容。其中valueString的格式如下’ equal to: equal to; not equal to: not equal to’。鍵值之間用冒號隔開,2項之間用分號隔開。注意:把recreateForm設為true,否則'setColProp'只在第一次調用時有效。

          2. var rowNum=parseInt($(this).getGridParam("records"), 10); 得到數據條數。

          3. jQuery("#list_d").clearGridData();清空數據。

          4. jQuery("#list").getCell(ids,"Key");獲取第ids行的key列。

          5. $("#list").jqGrid('setSelection', "1");選中第一行。放在loadComplete:中在gird加載完成的時候自動選中第一行。loadComplete:function(data){$("#list").jqGrid('setSelection', "1");

          }

          6. 對于像1中的可編輯的字段,可以設定rule,參見http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editrules

          7. 修改Option,以URL為例

          jQuery("#list_d").jqGrid('setGridParam',{url:"xxx.aspx",page:1}).trigger('reloadGrid');


          主站蜘蛛池模板: 伊人无码精品久久一区二区| 国产乱人伦精品一区二区 | 国产精品污WWW一区二区三区| 国产在线一区二区三区在线| 精品无码中出一区二区| 九九久久99综合一区二区| 日韩精品一区二区三区色欲AV | 人妻无码一区二区三区| 国产一区二区三区国产精品| 国产福利电影一区二区三区,日韩伦理电影在线福 | 日本不卡一区二区三区| 大屁股熟女一区二区三区| 久久精品一区二区国产| 亚洲A∨无码一区二区三区| 一区二区三区免费电影| 精品少妇ay一区二区三区| 又硬又粗又大一区二区三区视频| 久久一区二区明星换脸| 精品国产亚洲一区二区三区在线观看 | 亚洲一区二区三区深夜天堂| 国产精品一区二区资源| 在线观看亚洲一区二区| 免费视频精品一区二区| 日韩精品中文字幕无码一区| 狠狠综合久久av一区二区| 亚洲熟女一区二区三区| 日韩精品一区二区三区毛片 | 亚洲高清一区二区三区电影| 91福利国产在线观看一区二区 | 亚洲AV无码一区二区三区网址| 精品国产乱子伦一区二区三区 | 精品视频一区二区三区四区五区| 亚洲人成人一区二区三区| 一区二区手机视频| 亚洲AV噜噜一区二区三区| 国产成人精品无码一区二区| 国产色精品vr一区区三区| 亚洲综合av一区二区三区不卡| 亚洲精品一区二区三区四区乱码| 一区二区三区在线免费看| 亚洲一区二区三区深夜天堂|