乐于分享
好东西不私藏

AI 时代重新学 Go(九):error、errors.Is/As 和 panic 的边界

AI 时代重新学 Go(九):error、errors.Is/As 和 panic 的边界

前面聊到 context 和 panic/recover 的时候,我其实刻意绕开了一个更日常的问题:Go 的错误到底应该怎么传?

刚开始写 Go,很容易把错误处理理解成一堆重复的:

if err != nil {    return err}

写久了会发现,真正难的不是这三行,而是这几个判断:

  • • 这个错误要不要让上层能识别?
  • • 要不要把底层错误包出去?
  • • 调用方应该用字符串、哨兵值,还是错误类型判断?
  • • 多个错误同时发生时,返回哪个?
  • • panic 到底算不算错误处理?

这些问题不解决,项目大了以后错误会变成一团文本。日志里看着有信息,代码里却没法做判断。

Go 的 error 很简单:

type error interface {    Error() string}

只要一个类型实现了 Error() string,它就是 error。没有异常栈展开,没有 try/catch,函数把失败作为返回值交给调用方。

func LoadUser(ctx context.Context, id int64) (*User, error) {    user, err := repo.FindUser(ctx, id)    if err != nil {        return nil, err    }    return user, nil}

这看起来啰嗦,但好处也明显:失败路径就在代码路径上。调用方不能假装看不见,除非它故意写 _

我的经验是,Go 的错误处理要先问一句:调用方拿到这个错误后,能做什么不同的动作?

如果只能打印日志,错误字符串就够了。如果要分支处理,就要给它可判断的形状。

不要用字符串判断错误

最糟糕的写法是这样:

if strings.Contains(err.Error(), "not found") {    // ...}

这个判断非常脆。错误文案换一下、加个前缀、翻译一下,业务逻辑就坏了。

如果调用方真的需要知道“没找到”,最简单的办法是哨兵错误:

var ErrUserNotFound = errors.New("user not found")func FindUser(ctx context.Context, id int64) (*User, error) {    user, err := dbFindUser(ctx, id)    if err != nil {        if errors.Is(err, sql.ErrNoRows) {            return nil, ErrUserNotFound        }        return nil, fmt.Errorf("find user %d: %w", id, err)    }    return user, nil}

调用方不要直接 err == ErrUserNotFound,用 errors.Is

user, err := FindUser(ctx, id)if err != nil {    if errors.Is(err, ErrUserNotFound) {        return nil, nil    }    return nil, err}

errors.Is 的意义是:它不只看当前 error,也会沿着包装链往里找。

%w 不是更好看的 %v

Go 1.13 给 fmt.Errorf 加了 %w。从输出上看,%w 和 %v 很像:

return fmt.Errorf("load config: %w", err)

但语义完全不同。

%v 只是把错误文本拼进去:

return fmt.Errorf("load config: %v", err)

调用方只能看到字符串。

%w 会把原始错误包在新错误里:

return fmt.Errorf("load config: %w", err)

调用方可以继续这样判断:

if errors.Is(err, os.ErrNotExist) {    // 配置文件不存在}

所以 %w 不是“更现代的写法”,而是在声明 API 边界:我允许调用方看见里面这个错误。

这句话很重要。假设你的包内部用的是 database/sql

func GetUser(ctx context.Context, id int64) (*User, error) {    user, err := queryUser(ctx, id)    if err != nil {        return nil, fmt.Errorf("query user: %w", err)    }    return user, nil}

如果这里把 sql.ErrNoRows 包出去了,外部就可能写:

if errors.Is(err, sql.ErrNoRows) {    // ...}

以后你把存储从 MySQL 换成 Redis、HTTP、ES,外部代码还依赖 sql.ErrNoRows,这就是你自己暴露出去的兼容包袱。

更稳的写法是把内部错误翻译成自己的错误:

var ErrUserNotFound = errors.New("user not found")func GetUser(ctx context.Context, id int64) (*User, error) {    user, err := queryUser(ctx, id)    if err != nil {        if errors.Is(err, sql.ErrNoRows) {            return nil, fmt.Errorf("%w: id=%d", ErrUserNotFound, id)        }        return nil, fmt.Errorf("query user %d: %w", id, err)    }    return user, nil}

对外承诺的是 ErrUserNotFound,不是 sql.ErrNoRows

sentinel error 适合表达稳定分类

哨兵错误适合表达“稳定、少量、调用方真的会处理”的分类。

比如:

var (    ErrUserNotFound = errors.New("user not found")    ErrUserDisabled = errors.New("user disabled"))

这些错误代表业务状态,调用方看到后会走不同分支。

不适合把所有错误都做成哨兵:

var (    ErrOpenFileFailed     = errors.New("open file failed")    ErrDecodeJSONFailed   = errors.New("decode json failed")    ErrValidateNameFailed = errors.New("validate name failed"))

如果调用方不会针对它们做分支,只是日志里想知道发生在哪一步,用上下文包装就够了:

if err := dec.Decode(&cfg); err != nil {    return fmt.Errorf("decode config %s: %w", path, err)}

错误分类越多,API 承诺越重。不是不能做,是要确认调用方真的需要。

custom error type 适合携带结构化信息

有些错误不是一个分类能说清楚的。比如限流错误,调用方除了知道“被限流”,还想知道多久后重试。

这时用自定义错误类型:

type RateLimitError struct {    RetryAfter time.Duration}func (e *RateLimitError) Error() string {    return fmt.Sprintf("rate limited, retry after %s", e.RetryAfter)}

返回时:

func CallAPI(ctx context.Context, client *http.Client, url string) error {    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)    if err != nil {        return fmt.Errorf("build request: %w", err)    }    resp, err := client.Do(req)    if err != nil {        return fmt.Errorf("call api: %w", err)    }    defer resp.Body.Close()    if resp.StatusCode == http.StatusTooManyRequests {        return &RateLimitError{RetryAfter: time.Minute}    }    if resp.StatusCode >= 400 {        return fmt.Errorf("call api: status %d", resp.StatusCode)    }    return nil}

调用方用 errors.As 拿到具体类型:

if err := CallAPI(ctx, client, url); err != nil {    var rateErr *RateLimitError    if errors.As(err, &rateErr) {        timer := time.NewTimer(rateErr.RetryAfter)        defer timer.Stop()        select {        case <-ctx.Done():            return ctx.Err()        case <-timer.C:            return CallAPI(ctx, client, url)        }    }    return err}

errors.As 跟 errors.Is 一样,也会沿着错误链往里找。区别是:

  • • errors.Is 问的是:这是不是某个错误分类?
  • • errors.As 问的是:这条链里有没有某种错误类型?如果有,把它取出来。

包装错误时,把动作写清楚

我以前写过这种错误:

return fmt.Errorf("failed: %w", err)

这种信息基本没用。上层日志可能变成:

failed: failed: failed: EOF

好的错误包装应该说明当时在做什么:

return fmt.Errorf("read request body: %w", err)return fmt.Errorf("decode user payload: %w", err)return fmt.Errorf("insert user %d: %w", user.ID, err)

不要首字母大写,不要加句号。因为错误经常会继续被前缀包装:

return fmt.Errorf("create order: %w", err)

最后输出会像一句从外到内的调用链:

create order: insert user 42: context deadline exceeded

这比“系统异常”强太多。

errors.Join 解决的是多错误,不是主错误

Go 1.20 加了 errors.Join。它适合这种场景:你做了几件相互独立的事,可能有多个失败,任何一个都不该被吞掉。

比如批量关闭资源:

func CloseAll(closers ...io.Closer) error {    var errs []error    for _, c := range closers {        if err := c.Close(); err != nil {            errs = append(errs, err)        }    }    return errors.Join(errs...)}

errors.Join 会忽略 nil。如果全部都是 nil,它返回 nil。返回的错误里可以被 errors.Is 和 errors.As 检查:

if err := CloseAll(a, b, c); err != nil {    if errors.Is(err, os.ErrClosed) {        // 其中至少有一个错误匹配 os.ErrClosed    }    return err}

不要把 errors.Join 当成“顺便多塞一点上下文”的工具。

如果一个错误是主因,另一个只是清理失败,我更倾向于保留主因,再把清理失败写进日志,或者在确实需要时明确 join:

func WriteFile(path string, data []byte) (err error) {    f, err := os.Create(path)    if err != nil {        return fmt.Errorf("create file %s: %w", path, err)    }    deferfunc() {        if closeErr := f.Close(); closeErr != nil {            err = errors.Join(err, fmt.Errorf("close file %s: %w", path, closeErr))        }    }()    if _, err := f.Write(data); err != nil {        return fmt.Errorf("write file %s: %w", path, err)    }    return nil}

这里 join 的含义很明确:写入可能失败,关闭也可能失败,两者都和调用方有关。

context 错误不要吃掉

阻塞操作要带 context.Context,这个前面已经聊过。错误处理里还有一个配套原则:context.Canceled 和 context.DeadlineExceeded 不要被改造成普通业务失败。

func SyncProfile(ctx context.Context, id int64) error {    profile, err := remote.LoadProfile(ctx, id)    if err != nil {        return fmt.Errorf("load remote profile %d: %w", id, err)    }    if err := repo.SaveProfile(ctx, profile); err != nil {        return fmt.Errorf("save profile %d: %w", id, err)    }    return nil}

上层可以判断:

err := SyncProfile(ctx, id)switch {case err == nil:    return nilcase errors.Is(err, context.Canceled):    return errcase errors.Is(err, context.DeadlineExceeded):    return errdefault:    return fmt.Errorf("sync profile: %w", err)}

超时和取消不是“同步失败”这么简单。它们通常意味着请求生命周期结束了,后续重试、告警、日志级别都可能不同。

panic 不是 error 的高级形态

上一篇讲过 panic/recover 的机制。放到错误处理里,我的边界很简单:

  • • 用户输入错了,返回 error
  • • 网络超时了,返回 error
  • • 文件不存在,返回 error
  • • 数据库没查到,返回 error
  • • 调用方传了不可能接受的参数,可以 panic
  • • 程序走到了理论上不可能的分支,可以 panic
  • • 初始化阶段的硬依赖缺失,可以 panic 或直接退出

比如这种不要 panic:

func ParseAge(s string) int {    age, err := strconv.Atoi(s)    if err != nil {        panic(err)    }    return age}

用户传错年龄是正常错误:

func ParseAge(s string) (int, error) {    age, err := strconv.Atoi(s)    if err != nil {        return 0, fmt.Errorf("parse age %q: %w", s, err)    }    if age < 0 {        return 0, fmt.Errorf("age must be non-negative: %d", age)    }    return age, nil}

panic 更适合表达程序员错误:

func MustRegister(name string, h Handler) {    if name == "" {        panic("handler name must not be empty")    }    if h == nil {        panic("handler must not be nil")    }    registry[name] = h}

这种 API 名字里带 Must,调用方知道它会在不满足前置条件时 panic。

recover 应该在边界兜底,不要偷偷继续

HTTP 服务里常见的 recover 中间件是合理的:

func Recover(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        deferfunc() {            if v := recover(); v != nil {                log.Printf("panic: %v\n%s", v, debug.Stack())                http.Error(w, "internal server error", http.StatusInternalServerError)            }        }()        next.ServeHTTP(w, r)    })}

它的作用是保护进程,不是把 panic 当成业务错误吞掉。

不要这样写:

func Do() (err error) {    deferfunc() {        if v := recover(); v != nil {            err = fmt.Errorf("do failed: %v", v)        }    }()    // 大量正常业务逻辑    return nil}

这会让调用方分不清是普通失败,还是代码已经进入了不可信状态。

还有一个老坑:recover 只能捕获同一个 goroutine 里的 panic。你在父 goroutine 里 defer recover,挡不住子 goroutine 崩掉。

gofunc() {    deferfunc() {        if v := recover(); v != nil {            log.Printf("worker panic: %v\n%s", v, debug.Stack())        }    }()    runWorker()}()

每个 goroutine 的边界要自己兜。

我现在写错误处理的顺序

现在我基本按这个顺序想:

  1. 1. 这个失败是不是调用方能处理的稳定分类?是的话,定义 sentinel error,并承诺 errors.Is
  2. 2. 这个失败是否需要携带结构化字段?是的话,定义 custom error type,并让调用方用 errors.As
  3. 3. 底层错误是不是我的 API 契约?是才用 %w 暴露,不是就翻译成自己的错误。
  4. 4. 多个独立错误是否都需要返回?是才用 errors.Join
  5. 5. 这是正常失败还是程序员错误?正常失败返回 error,程序员错误才考虑 panic。

Go 的错误处理看起来朴素,其实是在逼你把 API 边界想清楚。

下一篇继续看边界,不过换一个入口:JSON。几乎所有 HTTP API 都绕不开 encoding/json,它那些看似小的兼容细节,最后都会变成线上接口契约。

参考资料

  • • Working with Errors in Go 1.13[1]
  • • Package errors[2]
  • • Go 1.20 Release Notes: Wrapping multiple errors[3]
  • • Defer, Panic, and Recover[4]

引用链接

[1] Working with Errors in Go 1.13: https://go.dev/blog/go1.13-errors[2] Package errors: https://pkg.go.dev/errors[3] Go 1.20 Release Notes: Wrapping multiple errors: https://go.dev/doc/go1.20#errors[4] Defer, Panic, and Recover: https://go.dev/blog/defer-panic-and-recover

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-06 11:05:55 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/718459.html
  2. 运行时间 : 0.233419s [ 吞吐率:4.28req/s ] 内存消耗:4,897.85kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=d9f003567a16899564c1a758a2053697
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001071s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001565s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.007150s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.001416s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001418s ]
  6. SELECT * FROM `set` [ RunTime:0.000543s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001597s ]
  8. SELECT * FROM `article` WHERE `id` = 718459 LIMIT 1 [ RunTime:0.001047s ]
  9. UPDATE `article` SET `lasttime` = 1780715156 WHERE `id` = 718459 [ RunTime:0.011892s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000731s ]
  11. SELECT * FROM `article` WHERE `id` < 718459 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001151s ]
  12. SELECT * FROM `article` WHERE `id` > 718459 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001062s ]
  13. SELECT * FROM `article` WHERE `id` < 718459 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001740s ]
  14. SELECT * FROM `article` WHERE `id` < 718459 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002550s ]
  15. SELECT * FROM `article` WHERE `id` < 718459 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.002117s ]
0.237449s