Go语言教程之边写边学:了解如何在 Go 中处理错误
编写程序时,需要考虑程序失败的各种方式,并且需要管理失败。 无需让用户看到冗长而混乱的堆栈跟踪错误。 让他们看到有关错误的有意义的信息更好。 正如你所看到的,Go具有panic和recover之类的内置函数来管理程序中的异常或意外行为。 但错误是已知的失败,你的程序应该可以处理它们。
Go的错误处理方法只是一种只需要if和return语句的控制流机制。 例如,在调用函数以从employee对象获取信息时,可能需要了解该员工是否存在。 Go处理此类预期错误的一贯方法如下所示:
employee, err := getInformation(1000)
if err != nil {
    // Something is wrong. Do something.
}
注意getInformation函数返回了employee结构,还返回了错误作为第二个值。 该错误可能为nil。 如果错误为nil,则表示成功。 如果错误不是nil,则表示失败。 非nil错误附带一条错误消息,你可以打印该错误消息,也可以记录该消息(更可取)。 这是在Go中处理错误的方式。 下一部分将介绍一些其他策略。
你可能会注意到,Go中的错误处理要求你更加关注如何报告和处理错误。 这正是问题的关键。 让我们看一些其他示例,以帮助你更好地了解Go的错误处理方法。
我们将使用用于结构的代码片段来练习各种错误处理策略:
package main

import (
    "fmt"
    "os"
)

type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

func main() {
    employee, err := getInformation(1001)
    if err != nil {
        // Something is wrong. Do something.
    } else {
        fmt.Print(employee)
    }
}

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    return employee, err
}

func apiCallEmployee(id int) (*Employee, error) {
    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}
从现在开始,我们将重点介绍如何修改getInformation、apiCallEmployee和main函数,以展示如何处理错误。

错误处理策略

当函数返回错误时,该错误通常是最后一个返回值。 正如上一部分所介绍的那样,调用方负责检查是否存在错误并处理错误。 因此,一个常见策略是继续使用该模式在子例程中传播错误。 例如,子例程(如上一示例中的getInformation)可能会将错误返回给调用方,而不执行其他任何操作,如下所示:
func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, err // Simply return the error to the caller.
    }
    return employee, nil
}

你可能还需要在传播错误之前添加更多信息。 为此,可以使用fmt.Errorf() 函数,该函数与我们之前看到的函数类似,但它返回一个错误。 例如,你可以向错误添加更多上下文,但仍返回原始错误,如下所示:

func getInformation(id int) (*Employee, error) {
    employee, err := apiCallEmployee(1000)
    if err != nil {
        return nil, fmt.Errorf("Got an error when getting the employee information: %v", err)
    }
    return employee, nil
}

另一种策略是在错误为暂时性错误时运行重试逻辑。 例如,可以使用重试策略调用函数三次并等待两秒钟,如下所示:

func getInformation(id int) (*Employee, error) {
    for tries := 0; tries < 3; tries++ {
        employee, err := apiCallEmployee(1000)
        if err == nil {
            return employee, nil
        }

        fmt.Println("Server is not responding, retrying ...")
        time.Sleep(time.Second * 2)
    }

    return nil, fmt.Errorf("server has failed to respond to get the employee information")
}
最后,可以记录错误并对最终用户隐藏任何实现详细信息,而不是将错误打印到控制台。 我们将在下一模块介绍日志记录。 现在,让我们看看如何创建和使用自定义错误。

创建可重用的错误

有时错误消息数会增加,你需要维持秩序。 或者,你可能需要为要重用的常见错误消息创建一个库。 在Go中,你可以使用errors.New() 函数创建错误并在若干部分中重复使用这些错误,如下所示:
var ErrNotFound = errors.New("Employee not found!")

func getInformation(id int) (*Employee, error) {
    if id != 1001 {
        return nil, ErrNotFound
    }

    employee := Employee{LastName: "Doe", FirstName: "John"}
    return &employee, nil
}
getInformation函数的代码外观更优美,而且如果需要更改错误消息,只需在一个位置更改即可。 另请注意,惯例是为错误变量添加Err前缀。
最后,如果你具有错误变量,则在处理调用方函数中的错误时可以更具体。 errors.Is() 函数允许你比较获得的错误的类型,如下所示:
employee, err := getInformation(1000)
if errors.Is(err, ErrNotFound) {
    fmt.Printf("NOT FOUND: %v\n", err)
} else {
    fmt.Print(employee)
}

用于错误处理的推荐做法

在Go中处理错误时,请记住下面一些推荐做法:
  • 始终检查是否存在错误,即使预期不存在。 然后正确处理它们,以免向最终用户公开不必要的信息。
  • 在错误消息中包含一个前缀,以便了解错误的来源。 例如,可以包含包和函数的名称。
  • 创建尽可能多的可重用错误变量。
  • 了解使用返回错误和panic之间的差异。 不能执行其他操作时再使用panic。 例如,如果某个依赖项未准备就绪,则程序运行无意义(除非你想要运行默认行为)。
  • 在记录错误时记录尽可能多的详细信息(我们将在下一部分介绍记录方法),并打印出最终用户能够理解的错误。
Go语言教程之边写边学:如何处理HTTP 错误

在Go中,可以使用net/http包来处理HTTP错误,该包为处理HTTP错误提供了内置支持。下面是一个示例代码片段,演示了如何在Go中处理HTTP错误:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	// send a GET request
	resp, err := http.Get("http://example.com")
	if err != nil {
		// handle error
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	// check for errors in the response status code
	if resp.StatusCode != http.StatusOK {
		// handle error
		fmt.Println("Error: unexpected status code:", resp.StatusCode)
		return
	}

	// process the response
	// ...
}

在此代码片段中,我们使用http.Get函数向http://example.com发送GET请求。如果在请求过程中发生错误,我们会处理它并退出程序。如果响应状态码不是http.StatusOK(即200),我们处理错误并退出程序。否则,我们会根据需要处理响应。 您还可以使用http.Response.StatusCode字段和http.Response.Body字段。

下面是演示此方法的示例代码片段:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	// send a GET request
	resp, err := http.Get("http://example.com")
	if err != nil {
		// handle error
		fmt.Println("Error sending request:", err)
		return
	}
	defer resp.Body.Close()

	// read the response body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// handle error
		fmt.Println("Error reading response body:", err)
		return
	}

	// check for errors in the response
	if resp.StatusCode != http.StatusOK {
		// handle error
		fmt.Println("Error:", resp.StatusCode, string(body))
		return
	}

	// process the response
	// ...
}

在此代码片段中,我们使用http.Get函数向http://example.com发送GET请求。如果在请求期间或读取响应正文时发生错误,我们会处理它并退出程序。然后,我们检查响应状态代码和响应正文是否存在错误。如果发生错误,我们会处理它并退出程序。否则,我们会根据需要处理响应。

TypeError: Illuminate\Routing\Router::group(): Argument #1 ($attributes) must be of type array, Closure given, called in D:\project\ibra-backend\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php on line 353 in file D:\project\ibra-backend\vendor\laravel\framework\src\Illuminate\Routing\Router.php on line 450
Route::group(function () {
        Route::get('/list', [\App\Http\Controllers\Controller::class, 'list']);
    });

group下只有一个路由会有如上报错。

git错误信息:The requested URL returned error: 403

如果你认为添加的sshkey,remote地址都正确,试一下清楚缓存。

git config --system --unset credential.helper

然后重新试一下。

docker中安装snpad:error: cannot communicate with server: Post "http://localhost/v2/snaps/core": dial unix /run/snapd.socket: connect: no such file or directory、

我发现了在docker容器中安装snapd的问题:目前不支持以这种方式运行snapd。

这个问题已经在snapcraft论坛上被问到了。snapd的依赖项之一是systemd,如果不重新启动或重新登录,snapd服务就无法正确初始化。根据所有发行版的文档,这是必需的程序,但显然在docker中不是一个选项。

在docker主机上安装snapd,在运行时将snapd套接字装入已安装snapd的容器中。

这里是官方回复:无法在 docker 映像(ubuntu:19.10)中安装 snapcraft snap) - snapcraft - snapcraft.io

npm错误信息:error:0308010C:digital envelope routines::unsupported

这是因为 node.js V17版本中最近发布的OpenSSL3.0, 而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响。故此以前的项目在升级 nodejs 版本后会报错。

修改package.json,在相关构建命令之前加入SET NODE_OPTIONS=--openssl-legacy-provider,然后正常运行npm run serve即可。

"scripts": {
   "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
   "build": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build"
},
php imagck读取pdf错误:attempt to perform an operation not allowed by the security policy PDF

这是ImageMagic中有权限配置文件,需要修改PDF相关的读写权限。

# 打开policy.xml文件

sudo nano /etc/ImageMagick-6/policy.xml

# 修改PDF相关权限,由none改为read|write

<policy domain="coder" rights="none" pattern="PDF" />

# 改为

<policy domain="coder" rights="read|write" pattern="PDF" />

 

  • 当前日期:
  • 北京时间:
  • 时间戳:
  • 今年的第:18周
  • 我的 IP:18.222.188.218
农历
五行
冲煞
彭祖
方位
吉神
凶神
极简任务管理 help
+ 0 0 0
Task Idea Collect