精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go 錯誤處理的藝術:告別 `if err != nil` 的千篇一律

開發 前端
本文將深入探討 Go 語言中三種核心的錯誤處理策略:哨兵錯誤、錯誤類型和不透明錯誤,并分享如何優雅地處理和包裝錯誤。

在 Go 語言中,if err != nil 是我們每天都會寫無數遍的代碼。然而,Go 的錯誤處理遠不止于此。理解并恰當地運用不同的錯誤處理策略,能讓你的代碼更健壯、更易讀、更便于調試。

本文將深入探討 Go 語言中三種核心的錯誤處理策略:哨兵錯誤、錯誤類型和不透明錯誤,并分享如何優雅地處理和包裝錯誤。

一、錯誤只是一種值

Go 語言將錯誤視為一種普通的值,這賦予了錯誤極大的靈活性,也帶來了如何有效處理它們的挑戰。

沒有一種“放之四海而皆準”的完美錯誤處理方法,而是需要根據具體場景選擇最合適的策略。

二、錯誤處理的三種核心策略

2.1 哨兵錯誤 (Sentinel Errors)

定義: 哨兵錯誤是指使用預先聲明的特定變量來表示錯誤條件。

示例:

package main

import(
"errors"
"fmt"
)

var ErrSomething = errors.New("something went wrong")

funcdoSomething()error{
// ... 業務邏輯 ...
return ErrSomething // 返回預定義的錯誤值
}

funcmain(){
	err :=doSomething()
if err == ErrSomething {// 通過等式運算符比較錯誤
		fmt.Println("Caught sentinel error: ErrSomething")
}elseif err !=nil{
		fmt.Printf("Caught other error: %v\n", err)
}
}

典型場景:

  • 標準庫中的 io.EOF (表示文件/流結束,而非真正的錯誤)。
  • syscall 包中更底層的錯誤常量,如 syscall.ENOENT (無此文件或目錄)。
  • path/filepath.SkipDir (指示 Walk 函數跳過當前目錄)。

缺點與弊端:

  • 缺乏靈活性: 哨兵錯誤是預聲明的固定值。一旦你使用 fmt.Errorf 為錯誤添加上下文信息,就會破壞其原始值,導致等式檢查失效。
err :=doSomething()
// 如果 doSomething 返回 fmt.Errorf("包裝: %w", ErrSomething),
// 那么 err == ErrSomething 將為 false。
  • 強制檢查 error.Error() 輸出(反模式): 當等式檢查失效時,調用者可能被迫檢查 err.Error() 的字符串輸出,看是否包含特定子串。這是一個嚴重的反模式,因為 Error() 方法的輸出是為人類閱讀設計的,其內容可能在不同版本或不同實現中發生變化,導致程序行為不穩定。
  • 成為公共 API 的一部分,造成強耦合: 如果你的公共函數或接口返回一個特定的哨兵錯誤,這個錯誤值必須被公開,并且調用者為了檢查該錯誤就必須導入定義它的包。這在兩個包之間建立了源代碼依賴,導致不必要的耦合。當項目變大時,這種模式極易引發導入循環和版本兼容性問題。

結論:應盡量避免在自己編寫的代碼中導出和使用哨兵錯誤值。 它們雖然在標準庫的少數特定場景下有用,但通常會帶來設計上的僵化和耦合。

2.2 錯誤類型 (Error Types)

定義: 錯誤類型是指你創建并實現了 error 接口的自定義類型。

示例:

package main

import(
"fmt"
"os"
)

// MyError 是一個自定義錯誤類型,包含文件、行號和消息
type MyError struct{
	Msg  string
	File string
	Line int
}

// Error 方法實現了 error 接口
func(e *MyError)Error()string{
return fmt.Sprintf("%s:%d: %s", e.File, e.Line, e.Msg)
}

funcreadFile(filename string)error{
_, err := os.Open(filename)
if err !=nil{
return&MyError{
			Msg:"failed to open file",
			File:"main.go",
			Line:42,
}
}
returnnil
}

funcmain(){
	err :=readFile("non_existent_file.txt")
switch e := err.(type){// 使用類型斷言或類型切換
casenil:
		fmt.Println("File read successfully.")
case*MyError:// 匹配自定義錯誤類型
		fmt.Printf("Custom error occurred on line %d: %s\n", e.Line, e.Msg)
default:// 其他未知錯誤
		fmt.Printf("Unknown error: %v\n", e)
}
}

優點:

  • 攜帶上下文信息: 錯誤類型可以包含額外的字段來存儲錯誤發生的詳細上下文(如文件路徑、操作類型、錯誤碼等),這比簡單的字符串更具表達力。
  • 可包裝底層錯誤: 像 os.PathError 這樣的錯誤類型,其內部包含一個 Err error 字段,可以包裝底層導致錯誤的根因。

缺點:

  • 依舊存在耦合: 盡管比哨兵錯誤靈活,但調用者仍然需要通過類型斷言或類型切換來檢查和處理特定錯誤類型。這意味著,如果你的公共 API 返回自定義錯誤類型,調用者為了處理它,仍然需要導入定義該錯誤類型的包,這仍然造成了一定程度的強耦合。
  • API 脆弱性: 一旦錯誤類型的結構發生變化(例如增刪字段),所有依賴該類型的調用者代碼可能都需要修改。

結論: 錯誤類型在封裝錯誤上下文方面有所改進,但仍不建議將其作為公共 API 的主要錯誤返回形式,因為它依然會引入強耦合。

2.3 不透明錯誤 (Opaque Errors)

定義: 不透明錯誤處理是指調用者只知道“有錯誤發生”,但不過多關心錯誤的具體內部細節。這是 Go 語言中最靈活且推薦的錯誤處理策略,因為它要求代碼和調用者之間的耦合度最小。

核心思想:只返回錯誤,而不對其內容做任何假設。 如果需要額外的上下文,則通過錯誤包裝(wrapping)機制在錯誤鏈上添加。

示例:

package bar

import"fmt"

funcFoo()error{
// 假設這里發生了一個內部錯誤
return fmt.Errorf("internal operation failed")
}
package main

import(
"fmt"
"your_project/bar"http:// 導入 bar 包
)

funcfn()error{
	err := bar.Foo()
if err !=nil{
// 這里不對 bar.Foo() 返回的錯誤做任何假設,直接返回或包裝
return fmt.Errorf("calling bar.Foo failed: %w", err)// 使用 %w 進行錯誤包裝
}
returnnil
}

funcmain(){
	err :=fn()
if err !=nil{
		fmt.Println("Error:", err)
// 輸出: Error: calling bar.Foo failed: internal operation failed
}
}

優點:

  • 最小耦合: 調用者無需導入定義錯誤的包,也無需關心錯誤的具體類型或值。
  • 易于調試: 通過錯誤包裝,可以在錯誤鏈上層層添加上下文信息,形成清晰的錯誤追蹤。
  • API 穩定性: 底層錯誤的實現細節可以自由變更,而不會破壞上層調用者的契約。

特例:基于行為的錯誤斷言 (Error Behaviors)

在少數需要根據錯誤性質做出決策的場景(例如網絡操作是否可重試),與其斷言錯誤是一個特定的類型或值,我們可以斷言錯誤是否實現了某個特定行為(通過接口)。

示例:

package main

import(
"errors"
"fmt"
)

// temporary 接口定義了判斷錯誤是否為臨時性的行為
type temporary interface{
Temporary()bool
}

// IsTemporary 判斷一個錯誤是否是臨時性的(可重試)
funcIsTemporary(err error)bool{
// Go 1.13+ 的 errors.As 函數是處理這種場景的推薦方式
var tempErr temporary
return errors.As(err,&tempErr)&& tempErr.Temporary()
}

// MyTemporaryError 實現了 temporary 接口
type MyTemporaryError struct{
	Msg string
}

func(e *MyTemporaryError)Error()string{return e.Msg }
func(e *MyTemporaryError)Temporary()bool{returntrue}

// MyPermanentError 不實現 temporary 接口
type MyPermanentError struct{
	Msg string
}

func(e *MyPermanentError)Error()string{return e.Msg }

funcmain(){
	err1 :=&MyTemporaryError{"network timeout"}
	err2 := fmt.Errorf("wrapped temporary error: %w", err1)
	err3 :=&MyPermanentError{"file not found"}

	fmt.Printf("Is '%v' temporary? %t\n", err1,IsTemporary(err1))// true
	fmt.Printf("Is '%v' temporary? %t\n", err2,IsTemporary(err2))// true (通過 errors.As 檢查包裝后的錯誤)
	fmt.Printf("Is '%v' temporary? %t\n", err3,IsTemporary(err3))// false
}

這里的關鍵是,你可以在不導入定義原始錯誤的包的情況下,檢查一個錯誤的行為。你只對錯誤是否具有 Temporary() 方法并返回 true 感興趣。

三、優雅處理錯誤:包裝與解包

Go 語言的錯誤處理不僅僅是 if err != nil,更重要的是如何為錯誤添加上下文并追蹤其根因。

3.1 為什么不要只 return err?

簡單的 return err 會丟失錯誤的上下文信息,使得調試變得異常困難。當錯誤層層傳遞到程序的頂層時,你可能只看到一個模糊的錯誤信息(例如 no such file or directory),而無法得知是哪個文件、在哪個函數、什么操作導致了這個錯誤。

錯誤的例子:

funcAuthenticateRequest(r *Request)error{
    err :=authenticate(r.User)// 假設 authenticate 內部返回 os.ErrNotExist
if err !=nil{
return err // 原始錯誤被直接返回,丟失上下文
}
returnnil
}

當這個錯誤最終被打印時,你可能只看到 no such file or directory,而不知道它與認證請求相關。

3.2 錯誤包裝 (Error Wrapping)

Go 1.13+ 引入了錯誤包裝的官方支持,使用 fmt.Errorf 配合 %w 動詞來包裝錯誤。這與流行的 github.com/pkg/errors 庫(現在已被官方特性吸收)的思想一致。

語法:fmt.Errorf("額外的上下文信息: %w", originalErr)

示例:

package main

import(
"fmt"
"os"
)

// ReadFile 將文件內容讀入內存
funcReadFile(path string)([]byte,error){
	f, err := os.Open(path)
if err !=nil{
// 包裝 os.Open 產生的錯誤,添加上下文 "open failed"
returnnil, fmt.Errorf("open failed: %w", err)
}
defer f.Close()

	buf, err := os.ReadFile(path)// 直接使用 os.ReadFile 更簡潔
if err !=nil{
// 包裝 os.ReadFile 產生的錯誤,添加上下文 "read failed"
returnnil, fmt.Errorf("read failed: %w", err)
}
return buf,nil
}

// ReadConfig 讀取配置文件
funcReadConfig()([]byte,error){
	home, err := os.UserHomeDir()
if err !=nil{
returnnil, fmt.Errorf("failed to get user home directory: %w", err)
}
	configPath := home +"/.settings.xml"http:// 假設配置文件路徑

// 包裝 ReadFile 產生的錯誤,添加上下文 "could not read config"
	config, err :=ReadFile(configPath)
return config, fmt.Errorf("could not read config from %s: %w", configPath, err)
}

funcmain(){
_, err :=ReadConfig()
if err !=nil{
// 打印完整的錯誤鏈
		fmt.Println(err)
// 期望輸出類似:could not read config from /home/user/.settings.xml: open failed: open /home/user/.settings.xml: no such file or directory
		os.Exit(1)
}
}

通過層層包裝,最終打印的錯誤信息將包含完整的上下文路徑,大大方便了調試。

3.3 錯誤解包 (Error Unwrapping)

當錯誤被包裝后,我們需要機制來恢復底層錯誤或檢查錯誤鏈中是否存在特定類型的錯誤。Go 1.13+ 提供了兩個核心函數:

  • errors.Unwrap(err error) error: 返回 err 中包含的下一個錯誤(如果 err 是一個包裝錯誤)。
  • errors.Is(err, target error) bool: 報告 err 鏈中是否包含與 target 值相同的錯誤。
  • errors.As(err error, target interface{}) bool: 查找 err 鏈中第一個與 target 類型匹配的錯誤,并將其值賦給 target。

示例:

package main

import(
"errors"
	"
"
)

var ErrNotFound = errors.New("not found")// 哨兵錯誤

type CustomNetError struct{
	Msg    string
	IsTemp bool
}

func(e *CustomNetError)Error()string{return e.Msg }
func(e *CustomNetError)Temporary()bool{return e.IsTemp }// 模擬臨時性錯誤行為

funcfetchData()error{
// return ErrNotFound // 假設返回哨兵錯誤
return&CustomNetError{Msg:"connection reset by peer", IsTemp:true}// 假設返回自定義錯誤類型并實現行為
}

funcprocessData()error{
	err :=fetchData()
if err !=nil{
return fmt.Errorf("failed to fetch data: %w", err)// 包裝錯誤
}
returnnil
}

funcmain(){
	err :=processData()

// 1. 使用 errors.Is 檢查錯誤鏈中是否存在特定的哨兵錯誤
if errors.Is(err, ErrNotFound){
		fmt.Println("Error: Data not found in the chain.")
}

// 2. 使用 errors.As 檢查錯誤鏈中是否存在特定類型的錯誤,并提取其值
var netErr *CustomNetError
if errors.As(err,&netErr){
		fmt.Printf("Error: A CustomNetError found in chain. Message: %s, IsTemporary: %t\n", netErr.Msg, netErr.IsTemp)
// 檢查是否是臨時錯誤(基于行為)
if netErr.Temporary(){
			fmt.Println("This is a temporary network error, could retry.")
}
}

// 3. 打印完整的錯誤鏈
	fmt.Println("\nFull error chain:")
	fmt.Println(err)
}

四、只處理一次錯誤

核心原則:處理一個錯誤意味著檢查錯誤值,并做出一個決策。 你應該只對一個錯誤做出一個決策。

  • 忽略錯誤(決策少于一個):這是最危險的,可能導致未預期的行為。
funcWrite(w io.Writer, buf []byte){
    w.Write(buf)// 錯誤被丟棄
}
  • 重復處理(決策多于一個):同樣有問題,會導致日志重復、上下文丟失。
funcWrite(w io.Writer, buf []byte)error{
_, err := w.Write(buf)
if err !=nil{
        log.Println("unable to write:", err)// 決策 1:記錄日志
return err // 決策 2:返回給調用者
}
returnnil
}
  • 這種情況下,頂層調用者會得到一個沒有上下文的原始錯誤,而日志中則充斥著重復的錯誤信息。

正確姿勢:使用錯誤包裝來添加上下文,并在程序的頂層進行最終處理。

// 盡可能在底層函數中包裝錯誤,添加上下文
funcWrite(w io.Writer, buf []byte)error{
_, err := w.Write(buf)
return fmt.Errorf("write failed: %w", err)// 只有一個決策:包裝并返回錯誤
}

// 在頂層(例如 main 函數、HTTP 請求處理器)集中處理錯誤:
funcmain(){
// ... 調用鏈 ...
	err :=Write(someWriter, someBuf)
if err !=nil{
		log.Printf("Application error: %v", err)// 最終處理:記錄日志,可能有棧追蹤
		os.Exit(1)
}
}

通過這種方式,你既為錯誤添加了豐富的上下文信息,又避免了重復處理和日志混亂。

總結

錯誤處理是 Go 語言編程中的一個核心話題。理解并實踐以下原則,將幫助你寫出更優雅、健壯和可維護的 Go 代碼:

  1. 避免哨兵錯誤作為公共 API,它們引入強耦合且靈活性差。
  2. 謹慎使用錯誤類型,它們可以攜帶上下文,但仍需考慮耦合問題。
  3. 擁抱不透明錯誤:這是最推薦的策略,只關心錯誤發生與否,通過錯誤包裝添加上下文。
  4. 基于行為而非類型或值斷言錯誤:當需要根據錯誤性質做決策時,定義接口來檢查錯誤的行為。
  5. 充分利用 fmt.Errorf 的 %w 動詞進行錯誤包裝,構建清晰的錯誤鏈。
  6. 使用 errors.Is 和 errors.As 解包錯誤,以檢查特定值或類型。
  7. 只處理一次錯誤:在底層添加上下文,在頂層進行最終決策(如記錄日志、返回 HTTP 錯誤等)。

掌握這些姿勢,你的 Go 程序將不再只是簡單的 if err != nil,而是充滿了優雅的錯誤處理藝術。

責任編輯:武曉燕 來源: GO語言圈
相關推薦

2018-03-22 16:13:48

劉海蘋果全面屏

2020-12-17 06:25:05

Gopanic 模式

2025-08-18 08:47:00

AI模型創作

2025-02-24 09:30:15

2017-05-25 16:12:00

互聯網

2023-02-03 16:39:39

ChatGPT算力人工智能

2014-11-17 10:05:12

Go語言

2021-04-29 09:02:44

語言Go 處理

2020-08-31 14:53:50

智能手機折疊屏平板

2024-06-05 08:47:20

Go語言方式

2021-09-27 15:33:48

Go 開發技術

2021-09-27 10:04:03

Go程序處理

2022-06-13 07:03:25

Go 語言怎么優化重

2025-03-31 00:29:44

2021-09-13 07:53:31

Go錯誤處理

2025-06-06 06:45:54

2022-09-05 08:55:15

Go2提案語法

2025-06-30 09:49:11

2025-09-05 01:55:00

Go并發錯誤項目
點贊
收藏

51CTO技術棧公眾號

九九热hot精品视频在线播放| 国产中文字幕在线| 亚洲美女91| 亚洲精品一区av在线播放| 欧美在线视频一二三| 加勒比一区二区| 日韩av电影资源网| 高清不卡在线观看av| 午夜免费日韩视频| 我不卡一区二区| 久久伊人久久| 欧美性生交大片免费| 一本一本a久久| 国产成人无码www免费视频播放| 国产亚洲在线| 日韩视频免费直播| 男人日女人下面视频| av免费在线一区二区三区| 国产精品色网| 精品国内自产拍在线观看| www.日日操| 超碰在线网址| 国产一区二区久久| 98精品国产自产在线观看| 国产69视频在线观看| 尤物视频在线看| 国产亚洲一区二区三区四区| 亚洲自拍偷拍第一页| www亚洲视频| 欧美精品97| 亚洲深夜福利网站| aaa毛片在线观看| 黄色av网站在线播放| 激情综合五月婷婷| 欧美中文在线观看| 久久国产精品波多野结衣| 欧美aaaa视频| 亚洲香蕉成人av网站在线观看 | 国产素人视频在线观看| 久久综合资源网| 国产精品大全| 国产露脸国语对白在线| 日韩成人午夜电影| 91av在线精品| 国产乡下妇女做爰| 影视一区二区| 久久精品小视频| 超碰人人干人人| 国语产色综合| 日韩精品亚洲元码| 喷水视频在线观看| 波多野结衣欧美| 日韩欧美国产高清| 一级片免费在线观看视频| 欧美高清视频| 国产精品无圣光一区二区| 欧美一区二区福利| 午夜av免费在线观看| 波多野结衣中文字幕一区| 99九九视频| www香蕉视频| 国产精品一区二区无线| 99re在线视频上| 国产jzjzjz丝袜老师水多| 韩国自拍一区| 亚洲男子天堂网| 五十路六十路七十路熟婆 | 久久动漫亚洲| 日本成人激情视频| 黄色一级视频免费看| 久久一二三区| 国产精品人成电影| 中文字幕欧美在线观看| 精品一区二区在线播放| 欧美激情免费在线| 久久伊人成人网| 亚洲电影在线| 清纯唯美亚洲综合| 欧美一级黄视频| 蜜桃视频在线观看一区二区| 在线免费观看一区| 91丨porny丨探花| 校园春色亚洲| 欧美在线免费播放| av中文字幕网址| 91午夜精品| 日韩经典中文字幕| 亚洲精品20p| 亚洲精品自拍| 亚洲精品在线免费播放| 亚洲精品理论片| 欧美丝袜一区| 欧美激情一区二区三区高清视频| 亚洲天堂一区在线观看| 美女国产一区二区三区| 成人国产1314www色视频| 亚洲av成人精品日韩在线播放| 国产偷国产偷亚洲高清人白洁| 日本黄色播放器| heyzo一区| 欧美日韩在线精品一区二区三区激情 | 邻居大乳一区二区三区| 国产精品白丝在线| 成年人网站国产| 日本精品网站| 亚洲国产99精品国自产| 中文字幕在线观看二区| 激情综合在线| 国产欧美精品一区二区三区-老狼| xxxx国产精品| 国产女人aaa级久久久级| www.亚洲视频.com| 欧美暴力调教| 亚洲第一视频在线观看| 国产精品高清无码在线观看| 欧美激情成人在线| 国产精欧美一区二区三区| 亚洲精品18p| 欧美经典一区二区| 水蜜桃色314在线观看| 四虎地址8848精品| 日韩精品在线免费观看视频| 三级影片在线看| 日本不卡二三区| 久久久这里只有精品视频| 中文在线字幕免费观| 成人国产亚洲欧美成人综合网| 亚洲欧美精品在线观看| 亚洲精品mv| 精品福利视频一区二区三区| 51精品免费网站| 这里只有精品在线| 国产精品福利在线观看网址| 亚洲AV成人无码一二三区在线| 亚洲男人天堂一区| 中文字幕第17页| 精品日韩在线| 日韩av片永久免费网站| 亚洲欧美日韩动漫| 亚洲大尺度视频在线观看| www.日本久久| 我不卡影院28| 国产精品专区第二| 国模精品一区二区| 欧美日韩中文在线观看| 给我免费观看片在线电影的| 欧美日韩爆操| 国产精品久久久久久久久久新婚| 免费在线国产| 日韩欧美高清在线视频| 人人妻人人澡人人爽人人精品| 狠狠干成人综合网| 国产精品中文字幕在线| 日本综合在线| 日本道色综合久久| 美女洗澡无遮挡| 日韩精品久久久久久| 色一情一乱一伦一区二区三区| 国产日韩另类视频一区| 国产亚洲欧美日韩精品| 少妇无套内谢久久久久| 欧美国产日本视频| www.com操| 久久精品国产99久久| 国产美女精彩久久| 老司机福利在线视频| 欧美一区二区三区视频| 欧美黄片一区二区三区| 免播放器亚洲| 免费国产一区二区| 在线成人视屏 | 91福利社在线观看| 精品熟妇无码av免费久久| 另类小说视频一区二区| 四虎免费在线观看视频| 亚洲国产欧美在线观看| 97超级碰在线看视频免费在线看| 日本国产在线| 精品视频123区在线观看| 美女的奶胸大爽爽大片| a美女胸又www黄视频久久| 国产欧美高清在线| 国产精品久久观看| 成人h视频在线观看| 亚洲黄色中文字幕| www.日韩.com| 高清乱码毛片入口| 91福利区一区二区三区| 欧美一区二区三区爽爽爽| 波多野结衣中文一区| 国产高清视频网站| 亚洲午夜极品| 日日噜噜噜噜夜夜爽亚洲精品| 蜜桃精品一区二区三区| 91av视频在线观看| 国产香蕉在线| 日韩视频免费观看高清在线视频| 三级视频在线观看| 中文字幕一区免费在线观看| 色哟哟无码精品一区二区三区| 久久久天天操| 欧美一级中文字幕| 久久av资源| 成人情视频高清免费观看电影| 性欧美18一19sex性欧美| 欧美另类极品videosbest最新版本| 亚洲 欧美 精品| 日韩一区国产二区欧美三区| 五月天激情四射| 一区二区三区欧美在线观看| mm131亚洲精品| 欧美午夜国产| 日韩亚洲视频| 久久人人爽人人爽人人片av不| 成人写真福利网| av在线日韩| 97人人爽人人喊人人模波多| 好吊日视频在线观看| 亚洲人成毛片在线播放| 男人天堂综合网| 91精品在线观看入口| 久久久精品毛片| 亚洲国产精品精华液网站| 三级黄色片在线观看| 久久综合成人精品亚洲另类欧美| 18深夜在线观看免费视频| 蜜臀av一区二区在线免费观看| 波多野结衣家庭教师在线播放| 综合在线一区| 亚洲欧美99| 欧美性感美女一区二区| 免费一区二区三区| 精品国产影院| 国产精品免费看一区二区三区| 精品国产一级| 91久久精品国产91久久性色| 91国拍精品国产粉嫩亚洲一区| 日韩在线视频国产| 毛片网站在线| 日韩国产精品视频| 色偷偷在线观看| 精品久久久久久久人人人人传媒| 国产午夜小视频| 一区二区成人在线| 国产稀缺精品盗摄盗拍| 国产精品二三区| 国产精品情侣呻吟对白视频| 国产日韩一级二级三级| 91成人在线免费视频| 久久久精品欧美丰满| 天天看片天天操| 免费观看久久久4p| www.亚洲高清| 久草精品在线观看| 思思久久精品视频| 国产在线精品不卡| 亚洲AV无码久久精品国产一区| 激情综合网av| 天天干天天曰天天操| 国产经典欧美精品| 日本精品一二三区| 爽好久久久欧美精品| 激情婷婷综合网| 欧美a一区二区| 一道本在线免费视频| 国产在线精品国自产拍免费| 日本黄色三级网站| 岛国精品在线观看| 成人性生活免费看| 久久这里只有精品视频网| 成人在线一级片| 国产精品高潮呻吟| caoporn91| 午夜精品久久久久久久99樱桃| 9i看片成人免费看片| 欧美日韩国产天堂| 国产成人av免费看| 日韩av网站导航| 成人综合影院| 欧美精品在线视频观看| 97天天综合网| 国产精品高潮视频| 色妞ww精品视频7777| 久久狠狠久久综合桃花| 精品久久不卡| 国产亚洲精品久久久久久久| 亚洲综合国产| 九九热精品国产| 成人涩涩免费视频| 91成人在线免费视频| 一区二区在线观看视频在线观看| 中文字幕精品三级久久久| 欧美在线观看视频在线| www.成人免费视频| 亚洲欧美日韩网| av网站在线免费| 欧美在线视频网站| 国产精品毛片aⅴ一区二区三区| 国产精品一区二区三区在线 | 水蜜桃一区二区| 综合天堂久久久久久久| 能在线观看的av网站| 国产精品 欧美精品| 538精品视频| 亚洲成av人片一区二区三区| 国产第一页在线观看| 欧美xingq一区二区| 97超碰人人在线| 高清欧美性猛交xxxx| 免费一区二区三区四区| 久久爱av电影| 欧美激情91| 黄色小视频免费网站| 久久综合九色综合97婷婷| 欧美国产在线看| 欧美日韩亚洲国产综合| 完全免费av在线播放| 成熟的女同志hd| 日本高清不卡在线观看| 女人18毛片一区二区三区| 久久天天躁夜夜躁狠狠躁2022| 在线免费av资源| 国产精品毛片一区视频| 亚洲最大av| www.99在线| 久久在线免费观看| 日本三级2019| 日韩欧美一区电影| 日韩美女网站| 国产精品电影观看| 亚洲人成亚洲精品| a在线视频观看| 成人黄色av电影| 久久免费视频99| 日韩一区二区在线观看视频播放| 永久免费在线观看视频| 国产精品视频在线播放| 国产精品三级| 日韩一级在线免费观看| 91麻豆免费在线观看| 男女视频免费看| 亚洲精品成人av| 极品美鲍一区| 精品免费国产| 国产情侣一区| 国产精品第七页| 精品成人国产在线观看男人呻吟| 日韩在线观看视频网站| 久久人人看视频| 国产精品毛片视频| 日本福利视频一区| 不卡的看片网站| 四虎精品永久在线| 国产视频在线一区二区| 欧美成人精品一区二区男人小说| 久久久久久久久久久久久久一区 | 欧美激情一二三| 亚洲超碰在线观看| 国产在线视频在线| 成人免费视频一区| 精品在线播放视频| 日韩精品丝袜在线| 欧美成人性网| 亚洲欧美久久234| 国产在线精品视频| 国产五月天婷婷| 亚洲精品一区二区三区婷婷月| 午夜欧美巨大性欧美巨大| 亚洲一卡二卡三卡| 国产美女视频一区| 免费毛片一区二区三区| 亚洲欧美精品suv| 青青青国产精品| 黄网站色视频免费观看| 91免费精品国自产拍在线不卡| 亚洲图片欧美日韩| 按摩亚洲人久久| 亚洲日本va| 免费观看精品视频| 国产精品免费视频观看| 成人激情四射网| 欧美最猛性xxxxx(亚洲精品)| 超碰成人久久| 91精品人妻一区二区三区四区| 欧美日韩在线视频一区| 在线观看黄色av| 国产成人精品自拍| 日韩国产在线观看| 久久久久久天堂| 一区二区三区动漫| 伊人久久影院| 国产精品igao| 亚洲午夜成aⅴ人片| 春暖花开成人亚洲区| 动漫美女被爆操久久久| 日韩精品国产精品| 国产午夜视频在线播放| 日韩在线视频网| 四虎5151久久欧美毛片| www激情五月|