标准库

package context 阅读更多

import "context" context包定义了Context类型,该类型自带 截止时间 取消信号 跨API边界或在两个进程之间的其他请求值 对服务端的传入请求会创建一个Context,服务端的传出调用会携带一个Context。客户端与服务端之间的函数调用链必须传递Context,其他可选的替代Context是一个使用WithCancel,WithDeadline,WithTimeout或WithValue创建的派生Context。当某个Context被取消后,基于它派生的所有Context也都会被取消。 WithCancel,WithDeadline和WithTimeout函数接受父Context并返回派生的子Context和一个CancelFunc函数。调用CancelFunc函数会取消子派生及子派生的子项,删除父项对子项的引用,并停止所有关联的计时器。调用CancelFunc函数失败会导致泄漏子派生及子派生子项,直到最开始的父项被取消或者计时器到达而被触发。go vet工具检查CancelFunc函数是否在所有控制流路径上使用。 使用Context的程序应遵循这些规则,以使各个包之间的接口保持一致,并启用静态分析工具来检查Context的传播: 不要将Context存储在结构类型中;而应该将Context明确传递给需要它的每个函数。 Context应该是第一个参数,通常命名为ctx: func DoSomething(ctx context.Context, arg Arg) error { // ... use ctx ... } 即使函数允许,也不要传递nil Context。如果不确定要使用哪个context,请传递context.TODO。 仅将Context值用于转换进程和API之间的请求数据,而不是将可选参数传递给函数。 可以将相同的Context传递给在不同goroutine中运行的函数;Context对于多个goroutine同时使用是安全的。 有关使用Context的服务示例代码,请参阅示例 变量 // Canceled是context取消时Context.Err返回的错误 var Canceled = errors.New("context canceled") // DeadlineExceeded是Context.Err在context截止时间过后返回的错误 var DeadlineExceeded error = deadlineExceededError{} 函数WithCancel func WithCancel(parent Context) (ctx Context, cancel CancelFunc) WithCancel返回带有新Done通道的父context的副本。返回的context的Done通道将会在调用返回的cancel函数或父context的Done通道关闭时被关闭(这两种情况中先发生的为准)。 取消此context会释放与其关联的资源,因此代码应在此context中运行的操作完成后立即调用cancel函数。 WithCancel示例 此示例演示了使用可取消的context来防止goroutine泄漏。在示例函数结束时,gen启动的goroutine将返回而不会泄漏。 // gen在单独的goroutine中生成整数将它们发送到返回的channel。 // gen的调用者需要取消一次context,他们消费生成的整数而不泄漏,内部的goroutine由gen开始 gen := func(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): return // returning not to leak the goroutine case dst <- n: n++ } } }() return dst } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // cancel when we are finished consuming integers for n := range gen(ctx) { fmt.Println(n) if n == 5 { break } } // 输出 1 2 3 4 5 函数WithDeadline func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) WithDeadline返回context的副本,且该副本的截止时间被调整为不迟于d。如果父context的截止时间早于d,则WithDeadline(parent,d)在语义上等同于父context。返回的context的Done通道在截止时间到期、调用返回的cancel函数时或父context的Done通道关闭时关闭(以先发生的情况为准)。 取消此context会释放与其关联的资源,因此代码应在此context中运行的操作完成后立即调用cancel函数。 WithDeadline示例 这个例子传递一个带有任意截止时间的context来告诉阻塞函数它应该在截止时间到达时放弃它的工作。 d := time.Now().Add(50 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d) // 尽管ctx将会过期,最佳实践是在任何情况下都要调用它的取消函数。 // 如果不这样做可能会导致保留context及其父context的活动时间超过我们的预期 defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) } 函数WithTimeout func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) WithTimeout函数返回WithDeadline(parent,time.Now().Add(timeout))。 取消此context会释放与其关联的资源,因此代码应在此context中运行的操作完成后立即调用cancel函数。 func slowOperationWithTimeout(ctx context.Context) (Result, error) { ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) defer cancel() // releases resources if slowOperation completes before timeout elapses return slowOperation(ctx) } WithTimeout示例 此示例传递具有超时的context,以告知阻塞函数在超时过后它应该放弃其工作。 // 传递一个带有超时时长的context来告诉一个正在阻塞的函数, // 它应该在超时时长过后放弃正在进的工作。 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // prints "context deadline exceeded" } 类型CancelFunc type CancelFunc func() CancelFunc告诉某个操作放弃它正在进行的工作。CancelFunc不会等待工作停止。第一次调用后,对CancelFunc的后续调用都不执行任何操作。 类型Context type Context interface { // Deadline函数返回完成工作的时间(该时间代表此context应该被取消)。 // 如果没有设置deadline,Deadline函数返回ok==false。 // 对Deadline函数的连续调用都返回相同的结果。 Deadline() (deadline time.Time, ok bool) // Done函数返回一个通道,当工作完成时通道将会被关闭,(这代表了这个context应该被取消)。 // 如果这个context不能被取消,Done函数也可能返回nil。 // 对Done函数的连续调用会返回相同的结果。 // 当取消被调用时,WithCancel安排Done通道关闭 // 当截止时间过期时,WithDeadline安排Done通道关闭 // 当超时时长到期时,WithTimeout安排Done通道关闭 // // Done提供用于select语句: // // // Stream使用DoSomething来生成值并将这些值发送出去, // // 直到DoSomething返回一个错误或者ctx.Done被关闭。 // func Stream(ctx context.Context, out chan<- Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // 查阅 https://blog.golang.org/pipelines 获取跟多如何使用Done通道来取消context的例子。 Done() <-chan struct{} // 如果Done没有关闭,Err函数返回nil。 // 如果Done已经关闭,Err函数返回non-nil来解释: // 如果是取消,为什么context被取消 // 如果是截止时间超时,为什么context的截止时间过了 // 在Err函数返回一个non-nil错误后, 持续的调用Err返回的都是同一个错误。 Err() error // Value函数返回与此context的key关联的value,如果没有value与key关联,则返回nil。 // 使用相同的key连续调用Value函数会返回相同的结果。 // 仅将context值用于切换进程和API的请求数据,而不是将可选参数传递给函数。 // key标识context中特定的值。想要在Context中存储值的函数通常在全局变量中分配一个key, // 然后使用该key作为context.WithValue和Context.Value的参数。 // key可以是支持判等的任何类型; 包应该将key定义为未导出类型以避免冲突。 // 定义Context key的包应该为使用该key存储的值提供类型安全的访问器: // // 包使用者定义一个User类型存储在Context中。 // package user // // import "context" // // // User是存储在context中的值的类型 // type User struct {...} // // // 定义在本包中的key是一个非导出类型。 // // 这避免了与定义在其他包中的key产生冲突。 // type key int // // // userKey是context中user.User值的key。它的未导出的。 // // 客户端使用user.NewContext和user.FromContext而不是直接使用这个key。 // var userKey key // // // NewContext返回一个新的Context其中携带值u。 // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext返回User的值,该值存储在ctx中(如果有)。 // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key interface{}) interface{} } Context跨越API边界携带截止时间,取消信号和其他跨API边界的值。Context的方法可以由多个goroutine同时调用。 方法Background func Background() Context Background()返回一个non-nil和空的Context。它永远不会被取消,没有值,也没有截止时间。它通常由主函数初始化和测试,并作为传入请求的顶级Context。 方法TODO func TODO() Context TODO()返回一个non-nil和空的Context。代码应该使用context.TODO当不清楚使用哪个Context或者它还不可用时(因为周围的函数尚未扩展为接受Context参数)。 方法WithValue func WithValue(parent Context, key, val interface{}) Context WithValue()返回父context的副本,其中与key关联的值为val。 仅将context值用于转换进程和API请求数据,而不是将可选参数传递给函数。 提供的key必须是可比较的,不应该是字符串类型或任何其他内置类型,以避免使用context的包之间的冲突。WithValue()的用户应该为key定义他们自己的类型。为了避免在指派接口时分配,context的key通常有具体类型的结构体。或者,导出context 的key的变量的静态类型应该是指针或接口。 WithValue示例 此示例演示如何将值传递给context以及如何检索它(如果存在)。 type favContextKey string f := func(ctx context.Context, k favContextKey) { if v := ctx.Value(k); v != nil { fmt.Println("found value:", v) return } fmt.Println("key not found:", k) } k := favContextKey("language") ctx := context.WithValue(context.Background(), k, "Go") f(ctx, k) f(ctx, favContextKey("color")) // 输出 found value: Go key not found: color

package exec 阅读更多

import "os/exec" exec包用于运行外部命令,它包装了os.StartProcess,使它更容易重映射到stdin和stdout,或者使用管道连接I/O并进行其他调整。 与C语言或者其他编程语言的“系统”库调用不同,os/exec包有意不调用系统shell,也不扩展任何glob patterns或处理一般情况下由shell完成的其他扩展,管道或重定向。 glob patterns是一种匹配模式,运用通配符来匹配一个文件列表。 exec包的行为更像是C的“exec”系列函数的功能。 要扩展glob patterns或者直接调用shell时: 要注意转义任何危险的输入 也可以使用path/filepath包的Glob函数 要扩展环境变量,请使用os包的ExpandEnv。 请注意,此包中的示例是在Unix系统中云的,可能无法在Windows上运行,并且不能在使用golang.org和godoc.org的Go Playground中运行。 变量 var ErrNotFound = errors.New("executable file not found in $PATH") ErrNotFound是路径搜索未能找到可执行文件时导致的错误。 函数LookPath func LookPath(file string) (string, error) LookPath在PATH环境变量命名的目录中搜索可执行文件file。如果file包含斜杠,则直接尝试搜索且不查询PATH。返回结果是绝对路径或相对于当前目录的相对路径。 示例 path, err := exec.LookPath("fortune") if err != nil { log.Fatal("installing fortune in your future") } fmt.Printf("fortune is available at %s\n", path) 类型Cmd type Cmd struct { // Path是所要运行命令的路径,这是唯一必须设置为非零值的字段。 // 如果是Path是相对的,则相对于{Dir}进行评估。 Path string // Args保存命令行参数,包括命令为Args[0]。 // 如果Args字段为空或为nil,则直接运行上述{Path}字段。 // 通常情况下,Path和Args都是通过调用Command来设置的。 Args []string // Env指定该进程的环境变量。每个条目都是“key=value”的格式。 // 如果Env为nil,那么新创建的进程使用当前进程的环境变量。 // 在此Env切片中,如果包含的环境变量中有重复的键值, // 那么每个重复的键值中只有最新的值会被使用。 Env []string // Dir指定命令的工作目录。 // 如果Dir是空字符串,那么{Run}会在发起调用的进程的当前目录中运行该命令。 Dir string // Stdin指定进程的标准输入。 // 如果Stdin为nil,则进程从null设备(os.DevNull)读取。 // 如果Stdin是*os.File,则进程的标准输入直接连接到该文件。 // 否则,在执行命令期间,单独的goroutine从Stdin读取并通过管道将数据传递给该命令。 // 在这种情况下,{Wait}将会一直等待直到goroutine停止拷贝数据, // 即,已经读取到Stdin的末尾(EOF或读取错误),或数据写入管道时出错。 Stdin io.Reader // Stdout和Stderr指定进程的标准输出和标准错误输出。 // 如果其中一个为nil,则{Run}将相应的文件描述符连接到空设备(os.DevNull)。 // 如果其中一个是*os.File,则进程相应的输出将直接连接到该文件。 // 否则,在命令执行期间,单独的goroutine通过管道从进程读取并将数据传递给对应的{Writer}。 // 在这种情况下,{Wait}将会一直等待直到goroutine读取到EOF或遇到错误。 // 如果Stdout和Stderr是同一个writer,并且具有可以判等(==)的类型,则一次最多只有一个goroutine调用写入函数。 Stdout io.Writer Stderr io.Writer // ExtraFiles指定新进程要继承的其他已打开文件。 // 它不包括标准输入,标准输出或标准错误输出。 // 如果非nil,那么条目i变为文件描述符3+i。 // Windows系统不支持ExtraFiles。 ExtraFiles []*os.File // SysProcAttr包含可选的操作系统特定属性。 // {Run}将它作为os.ProcAttr的Sys字段传递给os.StartProcess。 SysProcAttr *syscall.SysProcAttr // 一旦启动,Process就是底层进程。 Process *os.Process // ProcessState包含已退出进程的信息,在一次调用后无论处于{Wait}或{Run}都可用。 ProcessState *os.ProcessState // 包含已过滤或未导出的字段 } Cmd表示正在准备或运行的外部命令,在调用其Run,Output或CombinedOutput方法后,无法被重用。 函数Command func Command(name string, arg ...string) *Cmd Command返回Cmd结构以使用给定的参数执行指定的程序,它仅在返回的Cmd结构中设置Path和Args。 如果name不包含路径分隔符,则Command使用LookPath将name解析为完整路径(如果可能)。否则,它直接使用name作为Path。 返回的Cmd结构中Args字段是从命令name后紧跟的arg元素构造而来,因此在arg中不需要再包含命令name。例如,Command(“echo”,“hello”)。Args[0]始终是name,而不可能是已解析的路径。 在Windows上,进程将整个命令行作为单个字符串接收并执行自己的解析。Command使用与应用程序兼容的算法CommandLineToArgvW(这是最常用的方式)将Args组合并引用到命令行字符串中。值得注意的例外是msiexec.exe和cmd.exe(包括所有批处理文件batch files),它们具有不同的反引用算法。在这些或其他类似情况下,可以自己进行引用并在SysProcAttr.CmdLine中提供完整的命令行,让Args空着。 cmd := exec.Command("tr", "a-z", "A-Z") cmd.Stdin = strings.NewReader("some input") var out bytes.Buffer cmd.Stdout = &out err := cmd.Run() if err != nil { log.Fatal(err) } fmt.Printf("in all caps: %q\n", out.String())cmd := exec.Command("prog") cmd.Env = append(os.Environ(), "FOO=duplicate_value", // 重复值将被忽略 "FOO=actual_value", // 最新值将被使用 ) if err := cmd.Run(); err != nil { log.Fatal(err) } 函数CommandContext func CommandContext(ctx context.Context, name string, arg ...string) *Cmd CommandContext与Command类似,但包含上下文。 如果在命令自行完成之前context已经结束,则提供的context用于终止进程(通过调用os.Process.Kill)。 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil { // 这将在100毫秒后失败。 // 5秒的sleep进程将会被中断。 } 方法 (*Cmd)CombinedOutput func (c *Cmd) CombinedOutput() ([]byte, error) CombinedOutput运行命令并返回标准输出和标准错误错误输出的组合。 cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr") stdoutStderr, err := cmd.CombinedOutput() if err != nil { log.Fatal(err) } fmt.Printf("%s\n", stdoutStderr) 方法 (*Cmd)Output func (c *Cmd) Output() ([]byte, error) Output运行命令并返回其标准输出。任何返回的错误通常都是*ExitError类型。如果c.Stderr为nil,则Output填充ExitError.Stderr。 out, err := exec.Command("date").Output() if err != nil { log.Fatal(err) } fmt.Printf("The date is %s\n", out) 方法 (*Cmd)Run func (c *Cmd) Run() error Run启动指定的命令并等待它完成。 如果命令运行,在标准输入、标准输出和标准错误输出之间复制数据没有问题并且退出状态为零,那么返回的错误为nil。 如果命令启动但未成功完成,则返回的错误类型为*ExitError。对于其他情况,可能会返回其他错误类型。 如果正在被调用的goroutine已使用runtime.LockOSThread锁定操作系统线程并修改了任何可继承的OS级别线程状态(例如,Linux或Plan 9名称空间),则新进程将继承调用方的线程状态。 cmd := exec.Command("sleep", "1") log.Printf("Running command and waiting for it to finish...") err := cmd.Run() log.Printf("Command finished with error: %v", err) 方法 (*Cmd)Start func (c *Cmd) Start() error Start启动指定的命令,但不等待它完成。 一旦命令退出,Wait方法将返回退出状态码并释放相关资源。 cmd := exec.Command("sleep", "5") err := cmd.Start() if err != nil { log.Fatal(err) } log.Printf("Waiting for command to finish...") err = cmd.Wait() log.Printf("Command finished with error: %v", err) 方法 (*Cmd)StderrPipe func (c *Cmd) StderrPipe() (io.ReadCloser, error) StderrPipe返回一个管道,该管道将在命令启动时连接到命令的标准错误输出。 Wait将在看到命令退出后关闭管道,因此大多数调用者不需要自己关闭管道; 但是,需要注意的是在管道的所有读取完成之前调用Wait是不正确的。同样的,使用StderrPipe时使用Run也是不正确的。 有关习惯用法,请参阅StdoutPipe示例。 cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr") stderr, err := cmd.StderrPipe() if err != nil { log.Fatal(err) } if err := cmd.Start(); err != nil { log.Fatal(err) } slurp, _ := ioutil.ReadAll(stderr) fmt.Printf("%s\n", slurp) if err := cmd.Wait(); err != nil { log.Fatal(err) } 方法 (*Cmd)StdinPipe func (c *Cmd) StdinPipe() (io.WriteCloser, error) StdinPipe返回一个管道,该管道将在命令启动时连接到命令的标准输入。Wait查看到命令退出后将自动关闭管道。调用者只需要调用Close来强制管道更快关闭。例如,如果正在运行的命令在标准输入关闭之后不会退出,则调用者必须关闭管道。 cmd := exec.Command("cat") stdin, err := cmd.StdinPipe() if err != nil { log.Fatal(err) } go func() { defer stdin.Close() io.WriteString(stdin, "values written to stdin are passed to cmd's standard input") }() out, err := cmd.CombinedOutput() if err != nil { log.Fatal(err) } fmt.Printf("%s\n", out) 方法 (*Cmd)StdoutPipe func (c *Cmd) StdoutPipe() (io.ReadCloser, error) StdoutPipe返回一个管道,该管道将在命令启动时连接到命令的标准输出。 Wait将在看到命令退出后关闭管道,因此大多数调用者不需要自己关闭管道; 但是,值得注意的是在管道的所有读取完成之前调用Wait是不正确的。同样的,使用StdoutPipe时调用Run是不正确的。有关习惯用法,请参阅示例。 cmd := exec.Command("echo", "-n", `{"Name": "Bob", "Age": 32}`) stdout, err := cmd.StdoutPipe() if err != nil { log.Fatal(err) } if err := cmd.Start(); err != nil { log.Fatal(err) } var person struct { Name string Age int } if err := json.NewDecoder(stdout).Decode(&person); err != nil { log.Fatal(err) } if err := cmd.Wait(); err != nil { log.Fatal(err) } fmt.Printf("%s is %d years old\n", person.Name, person.Age) 方法 (*Cmd)Wait func (c *Cmd) Wait() error Wait等待命令退出并等待任何复制到标准输入或者从标准输出或标准错误输出复制完成。 该命令必须由Start启动。 如果命令运行,在标准输入、标准输出和标准错误输出之间复制数据没有问题且退出状态码为零,那么,返回的错误为nil。 如果命令无法运行或未成功完成,则错误类型为*ExitError。对于I/O问题,可能会返回其他错误类型。 如果c.Stdin,c.Stdout或c.Stderr中的任何一个不是*os.File,那么Wait也会等待相应的I/O循环复制到进程或从进程中复制完成。 Wait释放与Cmd相关的任何资源。 类型Error type Error struct { // Name是发生错误的文件名。 Name string // Err是潜在的错误。 Err error } Error是LookPath无法将文件归类为可执行文件时返回的。 方法 (*Error)Error func (e *Error) Error() string 类型ExitError type ExitError struct { *os.ProcessState // 如果没有收集标准错误输出,Stderr会保留Cmd.Output方法的标准错误输出的子集。 // 如果错误输出很长,Stderr可能只包含输出的前缀和后缀,中间替换为相关省略字节数的文本。 // 提供Stderr是用于代码调试,来包含在错误消息中。具有其他需求的用户应根据需要重定向Cmd.Stderr。 Stderr []byte } ExitError报告命令退出失败。 方法 (*ExitError)Error func (e *ExitError) Error() string

package flag 阅读更多

import "flag" flag包实现了命令行标识的解析。 使用方式 使用flag.String(),Bool(),Int()等来定义命令行标识。 方式一 定义一个整数标识-flagname,并将值保存在*int类型的指针ip中,其中1234为标识的默认值,”help message for flagname“是该标识的帮助信息: var ip = flag.Int("flagname", 1234, "help message for flagname") 方式二 使用Var()函数将该标识绑定到一个变量上,如下所示: var flagvar int // 定义标识要绑定的变量 func init() { flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname") } 方式三 创建一个自定义的标识(使用指针接收器),只要该标识满足Value接口,然后将它绑定到标识解析器,如果使用这样的变量来自定义标识,那么默认值就是变量的初始值。 flag.Var(&flagVal, "name", "help message for flagname") 在所有的标识都定义完成之后,执行下面的调用,将命令行解析到定义的标识中: flag.Parse() 然后可以直接使用这些标识: 如果直接使用标识本身,那么它们都是指针 如果将标识绑定到变量,那么它们就是值 fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) 解析后,所有标识对应的参数可用切片flag.Args()或用flag.Arg(i)一个个独立的获取到。参数从0开始通过flag.NArg()-1索引。 命令行标识语法 以下形式的命令行参数是允许的: -flag -flag=x -flag x // 仅限非布尔标识 使用-或者--都是可以,它们是等价的。由于命令可能包含的含义,布尔型的标识不允许使用第三种形式。 cmd -x * 其中*是Unix shell的通配符,如果有一个文件的名字是0、false等等时,会使命令产生歧义,因此必须使用-flag=false来关闭一个布尔型的标识。 停止解析标识的位置: 第一个非标识参数前(-是一个非标识参数) 在终止符--后 整型标识接收1234、0666、0x1234或者可能是负整数。 布尔型的标识可以如下: 1, t, T, true, TRUE, True 0, f, F, false, FALSE, False 持续时间(Duration)标识接受任何time.ParseDuration的有效输入。 默认的命令行标识集由顶级函数控制。FlagSet类型允许定义独立的标识集,例如在命令行界面中实现子命令。FlagSet的方法类似于命令行标识集的顶级函数。 示例 // 这些示例演示了flag包的更复杂用法 package main import ( "errors" "flag" "fmt" "strings" "time" ) // 示例1:名为“species”的单字符串标识,默认值为“gopher”。 var species = flag.String("species", "gopher", "the species we are studying") //示例2:共享变量的两个标识,因此我们可以使用简写。 //初始化顺序未定义,因此请确保两者都使用相同的默认值。必须使用init函数设置它们。 var gopherType string func init() { const ( defaultGopher = "pocket" usage = "the variety of gopher" ) flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage) flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)") } // 示例3:用户自定义的标识类型,是一个持续时间的切片 type interval []time.Duration // String方法用于格式户标识的值,是flag.Value接口的一部分。 // String方法的输出将用于诊断。 func (i *interval) String() string { return fmt.Sprint(*i) } // Set方法用于设置标识的值,也是flag.Value接口的一部分。 // Set方法的参数是string类型的被解析后用于设置该标识。 // 这是一个逗号分隔的列表,所以我们拆分它。 func (i *interval) Set(value string) error { // 如果我们允许多次设置标识来累积值,就需要将下面的if语句删除。 // 这将运行诸如此类的用法: -deltaT 10s -deltaT 15s 和其他的组合。 if len(*i) > 0 { return errors.New("interval flag already set") } for _, dt := range strings.Split(value, ",") { duration, err := time.ParseDuration(dt) if err != nil { return err } *i = append(*i, duration) } return nil } // 定义一个标识来累积持续时间。因为它有一个特殊的类型, // 我们需要使用Var函数,并在init期间创建该标识。 var intervalFlag interval func init() { // 将命令行标识绑定到intervalFlag变量并设置使用方式消息。 flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events") } func main() { // 有趣的是使用上面声明的变量,为了使flag包能够看到上面定义的标识,必须执行,通常在main(而不是init)的开头执行: flag.Parse() // 我们不在这里运行它,因为这不是main函数,并且测试套件已经解析了标识。 } 变量 var CommandLine = NewFlagSet(os.Args[0], ExitOnError) CommandLine是默认的命令行标识集,从os.Args解析。顶级函数(如BoolVar,Arg等)是CommandLine方法的包装器。 var ErrHelp = errors.New("flag: help requested") ErrHelp是在调用-help或-h标识但未定义此类标识时返回的错误。 var Usage = func() { fmt.Fprintf(CommandLine.Output(), "Usage of %s:\n", os.Args[0]) PrintDefaults() } Usage打印一条用法消息,该消息中记录所有已定义的命令行标识并输出到CommandLine.output(),默认情况下是输出到os.Stderr。只有当解析标识发生错误时才调用Usage,见类型部分中Flag结构体。 Usage变量是一个函数,可以更改为指向其他的自定义函数。默认情况下,它会打印一个简单的标题并调用PrintDefaults;有关输出格式及其控制方法的详细信息,请参阅PrintDefaults的文档或者查看下面的函数说明。 自定义的Usage函数会导致程序退出;默认情况下也是这样,因为命令行的错误处理策略设置为ExitOnError。 函数 func Arg(i int) string Arg返回第i个命令行参数。Arg(0)是处理完标识后的第一个剩余参数。如果请求的元素不存在,Arg将返回一个空字符串。 func Args() []string Args返回非标识命令行参数。 // Bool定义了一个带有指定名称,默认值和用法字符串的bool标识。返回值是存储标识值的bool变量的地址(指针) func Bool(name string, value bool, usage string) *bool{ } // BoolVar定义了一个带有指定名称,默认值和用法字符串的bool标识。参数p指向一个bool变量,用于存储标识的值。 func BoolVar(p *bool, name string, value bool, usage string){ }// Duration定义具有指定名称,默认值和用法字符串的time.Duration标识。返回值是存储标识值的time.Duration变量的地址。该标识接受time.ParseDuration可接受的值。 func Duration(name string, value time.Duration, usage string) *time.Duration{ } // DurationVar定义具有指定名称,默认值和用法字符串的time.Duration标识。参数p指向time.Duration变量,用于存储标识的值。该标识接受time.ParseDuration可接受的值。 func DurationVar(p *time.Duration, name string, value time.Duration, usage string){ }// Float64定义了一个带有指定名称,默认值和用法字符串的float64标识。返回值是存储标识值的float64变量的地址。 func Float64(name string, value float64, usage string) *float64{ } // Float64Var定义了一个带有指定名称,默认值和用法字符串的float64标识。参数p指向一个float64变量,用于存储该标识的值。 func Float64Var(p *float64, name string, value float64, usage string){ }// Int定义具有指定名称,默认值和用法字符串的int标识。返回值是存储标识值的int变量的地址。 func Int(name string, value int, usage string) *int{ } // IntVar定义了一个带有指定名称,默认值和用法字符串的int标识。参数p指向一个int变量,用于存储标识的值。 func IntVar(p *int, name string, value int, usage string){ } // Int64定义了一个带有指定名称,默认值和用法字符串的int64标识。返回值是存储标识值的int64变量的地址。 func Int64(name string, value int64, usage string) *int64{ } // Int64Var定义了一个带有指定名称,默认值和用法字符串的int64标识。参数p指向一个int64变量,用于存储该标识的值。 func Int64Var(p *int64, name string, value int64, usage string){ }// NArg返回的是处理标识后剩余的参数个数。 func NArg() int{ } // NFlag返回已设置的命令行标识的数量。 func NFlag() int{ }// Parse从os.Args[1:]中解析命令行标识。必须在定义所有标识之后并且在程序访问标识之前调用。 func Parse(){ } // Parsed报告是否已解析命令行标识。 func Parsed() bool{ } // 除非另外配置了输出位置,否则PrintDefaults会将内容打印在标准错误中。输出的内容为一个包含所有已经定义的命令行标识的默认设置的用法消息。 func PrintDefaults() // 对于整数值标识x,默认输出如下所示: -x int usage-message-for-x (default 7) 除了带有单字节名称的bool标识外,用法消息将另起一行显示。对于bool标识,省略类型,如果标识名称是一个字节,则用法消息将显示在同一行。 如果标识的默认值为零值,则会省略用法消息后面括号中的内容。在定义标识时,可以用反引号将标识的用法字符串中的某个名称引起来,那么,用法消息中的第一个被反引号引起来的内容将被视为要在消息中显示的默认值,并且在显示时将从消息中删除反引号。 如下所示: flag.String("I", "", "search `directory` for include files") // 用法消息输出如下 -I directory search directory for include files. 要更改标识的用法消息的输出位置,请调用CommandLine.SetOutput()。 func Set(name, value string) error{ } Set设置已经被命名的命令行标识的值。 // String定义具有指定名称,默认值和用法字符串的字符串标识。返回值是存储标识值的字符串变量的地址。 func String(name string, value string, usage string) *string{ } // StringVar定义具有指定名称,默认值和用法字符串的字符串标识。参数p指向一个字符串变量,用于存储标识的值。 func StringVar(p *string, name string, value string, usage string){ }// Uint定义了一个带有指定名称,默认值和用法字符串的uint标识。返回值是存储标识值的uint变量的地址。 func Uint(name string, value uint, usage string) *uint{ } // UintVar定义了一个带有指定名称,默认值和用法字符串的uint标识。参数p指向一个uint变量,用于存储标识的值。 func UintVar(p *uint, name string, value uint, usage string){ } // Uint64定义了一个带有指定名称,默认值和用法字符串的uint64标识。返回值是存储标识值的uint64变量的地址。 func Uint64(name string, value uint64, usage string) *uint64{ } // Uint64Var定义了一个带有指定名称,默认值和用法字符串的uint64标识。参数p指向一个uint64变量,用于存储该标识的值。 func Uint64Var(p *uint64, name string, value uint64, usage string){ }// UnquoteUsage从标识的用法字符串中提取被反引号引起来的名称并返回它,同时返回去掉反引号后的用法消息。 func UnquoteUsage(flag *Flag) (name string, usage string){ } // 给定如下用法消息 "a `name` to show" // UnquoteUsage输出的内容如下 ("name", "a name to show") // 如果没有反引号,则该名称是对标识值类型的有根据的猜测,如果该标识是布尔值,则为空字符串。 func Var(value Value, name string, usage string) Var定义具有指定名称和用法字符串的标识。 标识的类型和值由第一个参数表示,类型为Value,它通常包含用户定义的Value实现。 例如,调用者可以创建一个标识,通过为切片提供Value方法,将逗号分隔的字符串转换为字符串切片; 尤其是,Set会将逗号分隔的字符串分解为切片。 // Visit为每个fn调用以字典顺序访问命令行标识,它只访问已设置的那些标识。 func Visit(fn func(*Flag)){ } // VisitAll为每个fn调用以字典顺序访问命令行标识,它访问所有标识,甚至那些未设置的标识。 func VisitAll(fn func(*Flag)){ } 类型 // ErrorHandling定义了如果解析失败,FlagSet.Parse的行为方式。 type ErrorHandling int // 如果解析失败,这些常量反应了FlagSet.Parse的行为。 const ( ContinueOnError ErrorHandling = iota // 返回描述性错误 ExitOnError // 调用os.Exit(2). PanicOnError // 调用运行时恐慌并返回描述性错误 )// Flag表示标识的状态。 type Flag struct { Name string // 命令行上显示的名称 Usage string // 帮助信息/用法信息 Value Value // 设定的值 DefValue string // 用法信息的默认值(文本形式) } // Lookup返回指定命令行标识的Flag结构,如果不存在则返回nil。 func Lookup(name string) *Flag// FlagSet表示一组定义的标识。FlagSet的零值没有名称,并且具有ContinueOnError错误处理。 type FlagSet struct { // Usage是在解析标识发生错误时调用的函数。该字段是一个函数(不是方法), // 可以更改为指向自定义错误处理程序。调用Usage后会发生什么取决于ErrorHandling的设置; // 对于命令行,默认是ExitOnError,它将在调用Usage后退出程序。 Usage func(){} // 为了显示正常,此处没有大括号 // 包含已过滤或未导出的字段 } // NewFlagSet返回一个带有指定名称和错误处理属性的新的空标识集。如果名称不为空,则将在默认用法消息和错误消息中打印。 func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet{ } // Arg返回第i个参数。Arg(0)是处理完标识后剩余的第一个参数。如果请求的元素不存在,Arg将返回一个空字符串。 func (f *FlagSet) Arg(i int) string{ } // Args返回非标识的参数。 func (f *FlagSet) Args() []string{ } // Bool定义了一个带有指定名称,默认值和用法字符串的bool标识。返回值是存储标识值的bool变量的地址。 func (f *FlagSet) Bool(name string, value bool, usage string) *bool{ } // BoolVar定义了一个带有指定名称,默认值和用法字符串的bool标识。参数p指向一个bool变量,用于存储标识的值。 func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string){ } // Duration定义具有指定名称,默认值和用法字符串的time.Duration标识。返回值是存储标识值的time.Duration变量的地址。该标识接受time.ParseDuration可接受的值。 func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration{ } // DurationVar定义具有指定名称,默认值和用法字符串的time.Duration标识。参数p指向time.Duration变量,用于存储标识的值。该标识接受time.ParseDuration可接受的值。 func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string){ } // ErrorHandling返回标识集的错误处理行为。 func (f *FlagSet) ErrorHandling() ErrorHandling // Float64定义了一个带有指定名称,默认值和用法字符串的float64标识。返回值是存储标识值的float64变量的地址。 func (f *FlagSet) Float64(name string, value float64, usage string) *float64{ } // Float64Var定义了一个带有指定名称,默认值和用法字符串的float64标识。参数p指向一个float64变量,用于存储该标识的值。 func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string){ } // Init为标识集设置名称和错误处理属性。默认情况下,为零值的FlagSet使用空名称和ContinueOnError错误处理策略。 func (f *FlagSet) Init(name string, errorHandling ErrorHandling){ } // Int定义具有指定名称,默认值和用法字符串的int标识。返回值是存储标识值的int变量的地址。 func (f *FlagSet) Int(name string, value int, usage string) *int{ } // Int64定义了一个带有指定名称,默认值和用法字符串的int64标识。返回值是存储标识值的int64变量的地址。 func (f *FlagSet) Int64(name string, value int64, usage string) *int64{ } // Int64Var定义了一个带有指定名称,默认值和用法字符串的int64标识。参数p指向一个int64变量,用于存储该标识的值。 func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string){ } // IntVar定义了一个带有指定名称,默认值和用法字符串的int标识。参数p指向一个int变量,用于存储标识的值。 func (f *FlagSet) IntVar(p *int, name string, value int, usage string){ } // Lookup返回指定标识的Flag结构,如果不存在则返回nil。 func (f *FlagSet) Lookup(name string) *Flag{ } // NArg是处理标识后剩余的参数个数。 func (f *FlagSet) NArg() int{ } // NFlag返回已设置的标识数。 func (f *FlagSet) NFlag() int{ } // Name返回标识集的名称。 func (f *FlagSet) Name() string{ } // Output返回用法消和错误消息的输出目的地。如果未设置output或设置为nil,则返回os.Stderr。 func (f *FlagSet) Output() io.Writer{ } // Parse从参数列表中解析标识定义,该列表不包含命令的名称。必须在定义FlagSet中的所有标识之后并且在程序访问标识之前调用。如果未定义-help或-h,则返回值为ErrHelp。 func (f *FlagSet) Parse(arguments []string) error{ } // Parsed报告是否已调用f.Parse。 func (f *FlagSet) Parsed() bool{ } // 除非另外配置,否则PrintDefaults会把整个标识集中定义的标识的默认值输出到标准错误中,有关详细信息,请参阅上面的全局函数PrintDefaults的文档。 func (f *FlagSet) PrintDefaults(){ } // Set设置指定标识的值。 func (f *FlagSet) Set(name, value string) error{ } // SetOutput设置用法消息和错误消息的目的地。如果output设置为nil,则使用os.Stderr。 func (f *FlagSet) SetOutput(output io.Writer){ } // String定义具有指定名称,默认值和用法字符串的字符串标识。返回值是存储标识值的字符串变量的地址。 func (f *FlagSet) String(name string, value string, usage string) *string{ } // StringVar定义具有指定名称,默认值和用法字符串的字符串标识。参数p指向一个字符串变量,用于存储标识的值。 func (f *FlagSet) StringVar(p *string, name string, value string, usage string){ } // Uint定义了一个带有指定名称,默认值和用法字符串的uint标识。返回值是存储标识值的uint变量的地址。 func (f *FlagSet) Uint(name string, value uint, usage string) *uint{ } // Uint64定义了一个带有指定名称,默认值和用法字符串的uint64标识。返回值是存储标识值的uint64变量的地址。 func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64{ } // Uint64Var定义了一个带有指定名称,默认值和用法字符串的uint64标识。参数p指向一个uint64变量,用于存储该标识的值。 func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string){ } // UintVar定义了一个带有指定名称,默认值和用法字符串的uint标识。参数p指向一个uint变量,用于存储标识的值。 func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string){ } // Var定义具有指定名称和用法字符串的标识。标识的类型和值由第一个参数表示,类型为Value,它通常包含用户定义的Value实现。例如,调用者可以创建一个标识,通过为切片提供Value方法,将逗号分隔的字符串转换为字符串切片; 尤其是,Set会将逗号分隔的字符串分解为切片。 func (f *FlagSet) Var(value Value, name string, usage string) // Visit为每个fn调用以字典顺序访问标识,它只访问已设置的那些标识。 func (f *FlagSet) Visit(fn func(*Flag)) // VisitAll为每个fn调用以字典顺序访问标识,它访问所有标识,甚至那些未设置的标识。 func (f *FlagSet) VisitAll(fn func(*Flag))type Getter interface { Value Get() interface{} } Getter是一个允许检索Value内容的接口。因为它出现在Go1及其兼容性规则之后,所以它组合了Value接口,而不是成为value接口的一部分,此flag包提供的所有Value类型都满足Getter接口。 type Value interface { String() string Set(string) error } Value是存储在一个标识中的动态值的接口,它的默认值表示是字符串。 如果某个Value接口的IsBoolFlag()方法返回true,则命令行解析器使-name等效于-name=true,而不是使用下一个命令行参数。 为每个存在的标识,以命令行顺序调用且仅调用一次Set。flag包会使用零值接收器调用String方法,例如nil指针。 样例 package main import ( "flag" "fmt" "net/url" ) type URLValue struct { URL *url.URL } func (v URLValue) String() string { if v.URL != nil { return v.URL.String() } return "" } func (v URLValue) Set(s string) error { if u, err := url.Parse(s); err != nil { return err } else { *v.URL = *u } return nil } var u = &url.URL{} func main() { fs := flag.NewFlagSet("ExampleValue", flag.ExitOnError) fs.Var(&URLValue{u}, "url", "URL to parse") fs.Parse([]string{"-url", "https://golang.org/pkg/flag/"}) fmt.Printf(`{scheme: %q, host: %q, path: %q}`, u.Scheme, u.Host, u.Path) }

package http 阅读更多

import "net/http" http包提供HTTP客户端和服务端实现。 Get、Head、Post和PostForm发起HTTP(或HTTPS)请求: resp , err := http.Get("http://example.com/") ... resp, err := http.Post("http://example.com/upload","image/jpeg",&buf) ... resp, err := http.PostForm("http://example.com/form", url.Values{"Key":{"Value"}, "id":{"123"}}) 结束后,客户端必须关闭响应体: resp, err := http.Get("http://example.com") if err != nil { // handle error } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) 想要控制HTTP客户端的头、重定向策略和其他设置,需要创建一个Client: client := &http.Client{ CheckRedirect: redirectPolicyFunc, } resp, err := client.Get("http://example.com") // ... req, err := http.NewRequest("GET","http://example.com",nil) // ... req.Header.Add("if-None-Match",`W/"wyzzy"`) resp, err := client.Do(req) // ... 想要控制代理,TLS配置,keep-alive,压缩和其他设置,需要创建一个Transport: tr := &http.Transport{ MaxldleConns: 10, ldleConnTimeout: 30 * time.Second, DisableCompression: true, } client := &http.Client{Transport: tr} resp, err := client.Get("https://example.com") Client和Transport可以安全地被多个goroutine并发使用,为了高效应该只创建一次并重复使用。 ListenAndServe使用给定地址和handler启动一个HTTP服务端。这个handler通常是nil,这表示使用DefaultServeMux。Handle和HandleFunc将handler添加到DefaultServeMux: http.Handle("/foo",fooHandler) http.HandleFunc("/bar",func(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w, "Hello,%q", html.EscapeString(r.URL, Path)) }) log.Fatal(http.ListenAndServe(":8080", nil)) 创建一个自定义的Server来更好的控制服务端的行为: s := &http.Server{ Addr : ":8080", Handler: myHandler, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1<< 20, } log.Fatal(s.ListenAndServe()) 从Go 1.6开始,使用HTTPS时,http包对HTTP/2协议具有透明支持。 必须禁用HTTP/2的程序可以通过设置Transport.TLSNextProto(客户端设置)或者Server.TLSNextProto(服务端设置)的值为非nil的空map。或者,当前支持如下的GODEBUG环境变量: GODEBUG=http2client=0 // 禁用HTTP/2客户端支持 GODEBUG=http2server=0 // 禁用HTTP/2服务端支持 GODEBUG=http2debug=1 // 启动详细的HTTP/2调试日志 GODEBUG=http2debug=2 // 更详细的日志,包含 frame dumps Go的API兼容性保证不涵盖GODEBUG变量。在禁用HTTP/2支持之前,请报告所有问题:https://golang.org/s/http2bug 为了简化配置, http 包中的Transport和Server都自动启动HTTP/2支持。要为更复杂的配置启用HTTP/2,以使用低级别HTTP/2功能或使用Go的http2软件包的新版本,请直接导入 golang.org/x/net/http2 并使用其ConfigureTransport或ConfigureServer功能。通过golang.org/x/net/http2包手动配置HTTP/2优先于net/http包的内置HTTP/2支持。 Constants const ( MethodGet = "GET" MethodHead = "HEAD" MethodPost = "POST" MethodPut = "PUT" MethodPath = "PATCH" // RFC 5789 MethodDelete = "DELETE" MethodConnect = "CONNECT" MethodOptions = "OPTIONS" MethodTrace = "TRACE" ) 常见的HTTP方法。 除非另有说明,否则它们在RFC 7231第4.3节中定义。 const ( StatusContinue = 100 // RFC 7231, 6.2.1 StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2 StatusProcessing = 102 // RFC 2518, 10.1 StatusEarlyHints = 103 // RFC 8297 StatusOK = 200 // RFC 7231, 6.3.1 StatusCreated = 201 // RFC 7231, 6.3.2 StatusAccepted = 202 // RFC 7231, 6.3.3 StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4 StatusNoContent = 204 // RFC 7231, 6.3.5 StatusResetContent = 205 // RFC 7231, 6.3.6 StatusPartialContent = 206 // RFC 7233, 4.1 StatusMultiStatus = 207 // RFC 4918, 11.1 StatusAlreadyReported = 208 // RFC 5842, 7.1 StatusIMUsed = 226 // RFC 3229, 10.4.1 StatusMultipleChoices = 300 // RFC 7231, 6.4.1 StatusMovedPermanently = 301 // RFC 7231, 6.4.2 StatusFound = 302 // RFC 7231, 6.4.3 StatusSeeOther = 303 // RFC 7231, 6.4.4 StatusNotModified = 304 // RFC 7232, 4.1 StatusUseProxy = 305 // RFC 7231, 6.4.5 StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7 StatusPermanentRedirect = 308 // RFC 7538, 3 StatusBadRequest = 400 // RFC 7231, 6.5.1 StatusUnauthorized = 401 // RFC 7235, 3.1 StatusPaymentRequired = 402 // RFC 7231, 6.5.2 StatusForbidden = 403 // RFC 7231, 6.5.3 StatusNotFound = 404 // RFC 7231, 6.5.4 StatusMethodNotAllowed = 405 // RFC 7231, 6.5.5 StatusNotAcceptable = 406 // RFC 7231, 6.5.6 StatusProxyAuthRequired = 407 // RFC 7235, 3.2 StatusRequestTimeout = 408 // RFC 7231, 6.5.7 StatusConflict = 409 // RFC 7231, 6.5.8 StatusGone = 410 // RFC 7231, 6.5.9 StatusLengthRequired = 411 // RFC 7231, 6.5.10 StatusPreconditionFailed = 412 // RFC 7232, 4.2 StatusRequestEntityTooLarge = 413 // RFC 7231, 6.5.11 StatusRequestURITooLong = 414 // RFC 7231, 6.5.12 StatusUnsupportedMediaType = 415 // RFC 7231, 6.5.13 StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4 StatusExpectationFailed = 417 // RFC 7231, 6.5.14 StatusTeapot = 418 // RFC 7168, 2.3.3 StatusMisdirectedRequest = 421 // RFC 7540, 9.1.2 StatusUnprocessableEntity = 422 // RFC 4918, 11.2 StatusLocked = 423 // RFC 4918, 11.3 StatusFailedDependency = 424 // RFC 4918, 11.4 StatusTooEarly = 425 // RFC 8470, 5.2. StatusUpgradeRequired = 426 // RFC 7231, 6.5.15 StatusPreconditionRequired = 428 // RFC 6585, 3 StatusTooManyRequests = 429 // RFC 6585, 4 StatusRequestHeaderFieldsTooLarge = 431 // RFC 6585, 5 StatusUnavailableForLegalReasons = 451 // RFC 7725, 3 StatusInternalServerError = 500 // RFC 7231, 6.6.1 StatusNotImplemented = 501 // RFC 7231, 6.6.2 StatusBadGateway = 502 // RFC 7231, 6.6.3 StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 StatusInsufficientStorage = 507 // RFC 4918, 11.5 StatusLoopDetected = 508 // RFC 5842, 7.2 StatusNotExtended = 510 // RFC 2774, 7 StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 ) 注册在IANA上的HTTP状态码,查看: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml const DefaultMaxHeaderBytes = 1 << 20 // 1 MB DefaultMaxHeaderBytes是HTTP请求头的最大允许大小。可以通过设置Server.MaxHeaderBytes来覆盖它。 const DefaultMaxIdleConnsPerHost = 2 DefaultMaxIdleConnsPerHost是Transport的MaxIdleConnsPerHost的默认值。 const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT" TimeFormat是在HTTPHeader中生成时间时要使用的时间格式。就像time.RFC1123一样,但是将GMT硬编码为时区。格式化时间必须采用UTC格式才能生成正确的格式。 有关解析此时间格式的信息,请参见ParseTime。 const TrailerPrefix = "Trailer:" TrailerPrefix是ResponseWriter.Header的map的键的前缀(如果存在的话),表示map条目实际上是用于响应尾部的,而不是响应头的。ServeHTTP调用完成后,前缀将被删除,并且值将在尾部中发送。 此机制仅适用于在写入Header之前未知的Trailer。如果在写Header之前固定的或已知的尾Trailer,则首选普通的Go Trailer机制: https://golang.org/pkg/net/http/#ResponseWriter https://golang.org/pkg/net/http/#example_ResponseWriter_trailers Variables var ( // ErrNotSupported 是由Pusher的Push方法返回的,表示不可获得对HTTP/2的支持 ErrNotSupported = &ProtocolError{"feature not supported"} // 弃用 // net/http包中的任何方法都不会再返回 ErrUnexpectedTrailer // 调用者不应该将错误与这个变量进行比较 ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"} // 当请求的 Content-Type 不包含一个“boundary”参数时,Request.MultipartReader 返回 ErrMissingBoundary ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"} // 当请求的 Content-Type 不是 multipart/form-data 时,Request.MultipartReader 返回 ErrNotMultipart ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"} // 弃用 // net/http包中的任何方法都不会再返回 ErrHeaderTooLong // 调用者不应该将错误与这个变量进行比较 ErrHeaderTooLong = &ProtocolError{"header too long"} // 弃用 // net/http包中的任何方法都不会再返回 ErrShortBody // 调用者不应该将错误与这个变量进行比较 ErrShortBody = &ProtocolError{"entity body too short"} // 弃用 // net/http包中的任何方法都不会再返回 ErrMissingContentLength // 调用者不应该将错误与这个变量进行比较 ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"} )var ( // HTTP方法或响应代码不允许body时,ResponseWriter.Write调用返回ErrBodyNotAllowed ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body") // 当使用Hijacker接口时基础连接被劫持,ResponseWriter.Write 返回 ErrHijacked // 在被劫持的连接上进行零字节写入将返回ErrHijacked,而不会产生任何其他副作用 ErrHijacked = errors.New("http: connection has been hijacked") // 当 Handler 为Content-Length响应头设置一个长度,然后尝试写入比声明更多的字节时, // ResponseWriter.Write调用返回ErrContentLength ErrContentLength = errors.New("http: wrote more than the declared Content-Length") // 弃用 // net/http包中的任何方法都不会再返回 ErrWriteAfterFlush // 调用者不应该将错误与这个变量进行比较 ErrWriteAfterFlush = errors.New("unused") ) HTTP服务端使用的错误。 var ( // ServerContextKey是 context key。可以在带有 Context.Value 的 HTTP handler 中 // 使用它来访问启动 handler 的服务器,关联的值将是*Server类型 ServerContextKey = &contextKey{"http-server"} // LocalAddrContextKey是context key。 可以在带有Context.Value的HTTP handler中使用它来访问连接的本地地址 // 关联的值将为net.Addr类型。 LocalAddrContextKey = &contextKey{"local-addr"} )var DefaultClient = &Client{} DefaultClient是默认客户端,由Get,Head和Post使用。 var DefaultServeMux = &defaultServeMux DefaultServeMux是Serve使用的默认ServeMux。 var ErrAbortHandler = errors.New("net/http: abort Handler") ErrAbortHandler是一个中止panic值,用于中止handler。来自ServeHTTP的任何panic都会中止对客户端的响应,但是使用ErrAbortHandler进行panic也会抑制将堆栈跟踪记录到服务器的错误日志中。 var ErrBodyReadAfterClose = errors.New("http: invalid Read on closed Body") 在关闭请求或响应体后,读取请求或响应体时,将返回ErrBodyReadAfterClose。通常在HTTPhandler在其ResponseWriter上调用WriteHeader或Write后读取Body时,会发生这种情况。 var ErrHandlerTimeout = errors.New("http: Handler timeout")s 在已超时的handler上进行ResponseWriter的Write调用会返回ErrHandlerTimeout。 var ErrLineTooLong = internal.ErrLineTooLong 读取分块编码异常的请求或响应体时,将返回ErrLineTooLong。 var ErrMissingFile = errors.New("http: no such file") 当提供的文件字段不存在于请求中或者它不是一个文件字段中时,FormFile返回ErrMissingFile。 var ErrNoCookie = errors.New("http: named cookie not present") 未找到Cookie时,Request的Cookie方法将返回ErrNoCookie。 var ErrNoLocation = errors.New("http: no Location header in response") 如果不存在LocationHeader,则由Response的Location方法返回ErrNoLocation。 var ErrServerClosed = errors.New("http: Server closed") 调用Shutdown或Close之后,服务器的Serve,ServeTLS,ListenAndServe和ListenAndServeTLS方法返回ErrServerClosed。 var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol") ErrSkipAltProtocol是由Transport.RegisterProtocol定义的标记错误值。 var ErrUseLastResponse = errors.New("net/http: use last response") Client.CheckRedirect hooks 可以返回ErrUseLastResponse,以控制如何处理重定向。如果返回,则不发送下一个请求,并且返回最近的响应,且其Body未关闭。 var NoBody = noBody{} NoBody是一个没有字节的io.ReadCloser。读取始终返回EOF,而关闭始终返回nil。可以在传出客户端请求中使用它来明确表示请求的字节数为零。也可以很容易的将Request.Body设置为nil。 func CanonicalHeaderKey func CanonicalHeaderKey(s string) string CanonicalHeaderKey返回header key s 的规范格式。规范化将第一个字母和连字符后的任何字母转换为大写;其余的将转换为小写。例如,"accept-encoding"的规范格式是"Accept-Encoding"。如果 s 包含空格或无效的header field bytes,则返回它而无需进行任何修改。 func DetectContentType func DetectContentType(data []byte) string DetectContentType实现在https://mimesniff.spec.whatwg.org/上描述的算法,以确定给定数据的Content-Type。它最多考虑前512个字节的数据。 DetectContentType始终返回有效的MIME类型:如果无法确定更具体的类型,则返回"application/octet-stream"。 func Error func Error(w ResponseWriter, error string, code int) Error回复带有特定错误消息和HTTP代码的请求。否则,它不会结束请求;调用者应确保不再对w进行写操作。错误消息应为纯文本。 func Handle func Handle(pattern string, handler Handler) Handle在DefaultServeMux中注册给定模式的handler。ServeMux的文档说明了如何匹配模式。 Handle Example package main import ( "fmt" "log" "net/http" "sync" ) type countHander struct{ mu sync.Mutex // guards n n int } func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){ h.mu.Lock() defer h.mu.Unlock() h.n++ fmt.Fprintf(w, "count is %d\n", h.n) } func main(){ http.Handle("/count",new(countHandler)) log.Fatal(http.ListenAndServe(":8080",nil)) } func HandleFunc func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) HandleFunc在DefaultServeMux中注册给定模式的处理函数。ServeMux的文档说明了如何匹配模式。 HandleFunc Example h1 := func(w http.ResponseWriter, _ *http.Request){ io.WriteString(w, "Hello from a HandleFunc #1!\n") } h2 := func(w http.ResponseWriter, _ *http.Request){ io.WriteString(w,"Hello from a HandleFunc #2!\n") } http.HandleFunc("/", h1) http.HandleFunc("/endpoint", h2) log.Fatal(http.ListenAndServe(":8080",nil)) func ListenAndServe func ListenAndServe(addr string, handler Handler) error ListenAndServe监听TCP网络地址addr,然后调用带有handler的Serve来处理传入连接上的请求。能够接受的连接需要配置为启用TCP keep-alives。 该handler通常为nil,在这种情况下,将使用DefaultServeMux。 ListenAndServe始终返回非nil错误。 ListenAndServe Example helloHandler := func(w http.ResponseWriter, req *http.Request){ io.WriteString(w,"Hello,world!\n") } http.HandlerFunc("/hello",helloHandler) log.Fatal(http.ListenAndServe(":8080",nil)) func ListenAndServeTLS func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error ListenAndServeTLS的行为与ListenAndServe相同,不同之处在于它需要HTTPS连接。此外,必须提供包含服务器证书和匹配私钥的文件。如果证书是由证书颁发机构签名的,则certFile应该是服务器证书,任何中间件和CA证书的串联。 ListenAndServeTLS Example http.HandlerFunc("/",func(w http.ResponseWriter, req *http.Request){ io.WriteString(w,"Hello,TLS!\n") }) // One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem log.Printf("About to listen on 8443. Go to https://127.0,0.1:8443/") err := http.ListenAndServeTLS(":8443","cert.pem","key.pem",nil) log.Fatal(err) func MaxBytesReader func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser MaxBytesReader与io.LimitReader相似,但旨在限制传入请求体的大小。与io.LimitReader相比,MaxBytesReader的结果为ReadCloser,对于超出限制的Read返回非EOF错误,并在调用其Close方法时关闭底层reader。 MaxBytesReader可以防止客户端意外或恶意发送大请求并浪费服务器资源。 func NotFound func NotFound(w ResponseWriter, r *Request) NotFound回复请求,并显示HTTP 404 not found错误。 func ParseHTTPVersion func ParseHTTPVersion(vers string) (major, minor int, ok bool) ParseHTTPVersion解析HTTP版本字符串。 "HTTP/1.0"返回(1,0,true)。 func ParseTime func ParseTime(text string) (t time.Time, err error) ParseTime解析时间header(例如Date: header),尝试使用HTTP/1.1允许的三种格式:TimeFormat,time.RFC850和time.ANSIC。 func ProxyFromEnvironment func ProxyFromEnvironment(req *Request) (*url.URL, error) ProxyFromEnvironment返回用于给定请求的代理的URL,如环境变量HTTP_PROXY,HTTPS_PROXY和NO_PROXY(或其小写版本)所指示。对于HTTPS请求,HTTPS_PROXY优先于HTTP_PROXY。 环境值可以是完整的URL或"host[:port]",在这种情况下,假定使用"http"协议。如果值的格式不同,则返回错误。 如果环境中未定义任何代理,则返回nil URL和nil错误,或者不应将代理用于这样的请求(如NO_PROXY所定义)。 在特殊情况下,如果req.URL.Host为"localhost"(有或没有端口号),则将返回nil URL和nil错误。 func ProxyURL func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) ProxyURL返回一个代理函数(在Transport中使用),该函数始终返回相同URL。 func Redirect func Redirect(w ResponseWriter, r *Request, url string, code int) Redirect通过重定向到URL来响应请求,URL可能是相对于请求路径的路径。 返回的状态码应在3xx范围内,通常为StatusMovedPermanently(301),StatusFound(302)或StatusSeeOther(303)。 如果尚未设置Content-Type Header,Redirect会将其设置为 "text/html; charset=utf-8" 并编写一个小的HTML。将Content-Type Header设置为任何值(包括nil)将禁用该行为。 func Serve func Serve(l net.Listener, handler Handler) error Serve接受侦听器l上传入的HTTP连接,从而为每个侦听器创建一个新的服务goroutine。服务goroutine读取请求,然后调用handler以回复请求。该handler通常为nil,在这种情况下,将使用DefaultServeMux。 仅当侦听器返回*tls.Conn连接并且在TLSConfig.NextProtos中将它们配置为"h2"时,才启用HTTP/2支持。Serve始终返回非nil错误。 func ServeContent func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) ServeContent使用提供的ReadSeeker中的内容回复请求。ServeContent优于io.Copy的主要好处是它可以正确处理Range请求,设置MIME类型并处理If-Match,If-Unmodified-Since,If-None-Match,If-Modified-Since和If-Range 请求。 如果未设置响应的Content-TypeHeader,则ServeContent首先尝试从名称的文件扩展名中推断出类型,如果失败,则退回到读取内容的第一块并将其传递给DetectContentType。否则该名称未使用。特别是它可以为空,并且永远不会在响应中发送。 如果modtime不是零时间或Unix时期,则ServeContent会将其包含在响应的Last-Modified Header中。如果请求中包含If-Modified-Since Header,则ServeContent使用modtime来决定是否需要发送内容。 内容的Seek方法必须起作用:ServeContent使用对内容结尾的查找来确定其大小。 如果调用方设置了按照RFC 7232第2.3节格式化的w的ETagHeader,则ServeContent使用它来处理使用If-Match,If-None-Match或If-Range的请求。 请注意,*os.File实现了io.ReadSeeker接口。 func ServeFile func ServeFile(w ResponseWriter, r *Request, name string) ServeFile使用命名文件或目录的内容答复请求。 如果提供的文件或目录名称是相对路径,则会相对于当前目录进行解释,并且可能会升至父目录。 如果提供的名称是根据用户输入构造的,则应在调用ServeFile之前对其进行清理。 作为预防措施,ServeFile将拒绝r.URL.Path包含“..”路径元素的请求; 这样可以防止调用者可能不安全地使用filepath.Join而不清理它,然后使用该filepath.Join结果作为name参数。 作为另一种特殊情况,ServeFile将r.URL.Path以“/index.html”结尾的任何请求重定向到同一路径,而没有最终的“index.html”。 为避免此类重定向,请修改路径或使用ServeContent。 除了这两种特殊情况外,ServeFile不使用r.URL.Path来选择要提供的文件或目录。 仅使用name参数中提供的文件或目录。 func ServeTLS func ServeTLS(l net.Listener, handler Handler, certFile, keyFile string) error ServeTLS在侦听器l上接受传入的HTTPS连接,从而为每个侦听器创建一个新的服务goroutine。 服务goroutine读取请求,然后调用handler以回复请求。 该handler通常为nil,在这种情况下,将使用DefaultServeMux。 此外,必须提供包含服务器证书和匹配私钥的文件。 如果证书是由证书颁发机构签名的,则certFile应该是服务器证书,任何中间件和CA证书的串联。 ServeTLS始终返回非nil错误。 func SetCookie func SetCookie(w ResponseWriter, cookie *Cookie) SetCookie将Set-Cookie Header添加到提供的ResponseWriter的Header中。提供的cookie必须具有有效的名称。无效的cookie可能会被静默删除。 func StatusText func StatusText(code int) string StatusText返回HTTP状态代码的文本。如果状态码未知,它将返回空字符串。 type Client type Client struct { // Transport 指定发出单个HTTP请求的机制。 // 如果为nil,则使用DefaultTransport。 Transport RoundTripper // CheckRedirect指定用于处理重定向的策略。 如果CheckRedirect不为nil,则客户端将在执行 HTTP重定向之前调用它。 // 参数req和via是即将到来的请求和已发出的请求,先到达的先发出。 // 如果CheckRedirect返回错误,则客户端的Get方法将返回先前的Response(关闭该响应体)和CheckRedirect的错误(包装在url.Error中),而不是发出Request请求。 // 作为一种特殊情况,如果CheckRedirect返回ErrUseLastResponse,则返回最近的响应,且其响应体未关闭,并返回nil错误。 // 如果CheckRedirect为nil,则客户端使用其默认策略,该策略将在连续10个请求后停止。 CheckRedirect func(req *Request, via []*Request) error // Jar 指定cookie jar。Jar用于将相关cookie插入每个出站请求,并使用每个入站Response的cookie值进行更新。 // 客户端遵循的每个重定向都会咨询Jar。 如果Jar为nil,则仅当在Request上显式设置cookie时,才发送cookie。 Jar CookieJar // Timeout 指定此客户端发出的请求的时间限制。 超时包括连接时间,任何重定向和读取响应Body。 // 在Get,Head,Post或Do返回之后,计时器保持运行状态,并且将中断Response.Body的读取。 // Timeout为零表示没有超时。 客户端取消对基础传输的请求,就像请求的context结束一样。 // 为了兼容性,如果找到,客户端还将在Transport上使用已经弃用的CancelRequest方法。 // 新的RoundTripper实现应使用请求的context进行取消,而不是实现CancelRequest。 Timeout time.Duration } Client是HTTP客户端。它的零值(DefaultClient)是使用DefaultTransport的可用客户端。 客户端的传输通常具有内部状态(缓存的TCP连接),因此应重用客户端,而不是根据需要创建客户端。客户端可以安全地被多个goroutine并发使用。 客户端比RoundTripper(例如Transport)更高级别,并且还处理HTTP详细信息,例如cookie和重定向。 执行重定向时,客户端将转发在初始请求上设置的所有Header,但以下情况除外: 将诸如“Authorization”,“ WWW-Authenticate”和“ Cookie”之类的敏感Header转发到不受信任的目标时。当重定向到与子域不匹配或与初始域不完全匹配的域时,将忽略这些Header。例如,从“ foo.com”重定向到“ foo.com”或“ sub.foo.com”将转发敏感Header,但重定向到“ bar.com”则不会。 用非零值的Cookie Jar转发“ Cookie”Header时。由于每个重定向可能会更改Cookie Jar的状态,因此重定向可能会更改初始请求中设置的Cookie。当转发“ Cookie”Header时,任何突变的cookie都将被省略,并期望Jar将插入具有更新值的那些突变的cookie(假设原点匹配)。如果Jar为零,则将转发原始cookie,而不进行任何更改。 func (*Client) CloseIdleConnections func (c *Client) CloseIdleConnections() CloseIdleConnections关闭其Transport上先前请求建的现在处于“keep-alive”状态的所有连接。 它不会中断当前正在使用的任何连接。 如果客户端的Transport没有CloseIdleConnections方法,则此方法不执行任何操作。 func (*Client) Do func (c *Client) Do(req *Request) (*Response, error) Do 按照客户端上配置的策略(例如重定向,Cookie,身份验证)发送HTTP请求并返回HTTP响应。 如果是由客户端策略(例如CheckRedirect)或无法连接HTTP(例如网络连接问题)引起的,则返回错误。非2xx状态代码不会引起错误。 如果返回的错误为nil,则响应将包含一个非nil的响应体,用户希望将其关闭。如果未同时将Body读入EOF并关闭,则客户端的底层RoundTripper(通常是Transport)可能无法将与服务器的持久TCP连接重新用于后续的“keep-alive”请求。 请求体(如果非nil)将被底层Transport关闭,即使发生错误也是如此。 出错时,任何响应都可以忽略。仅当CheckRedirect失败并且返回的Response.Body已关闭时,才会出现具有非nil错误的非nil响应。 通常,将使用Get,Post或PostForm代替Do。 如果服务器回复重定向,则客户端首先使用CheckRedirect函数来确定是否应遵循重定向。如果允许,则301、302或303重定向会导致后续请求使用HTTP方法GET(如果原始请求为HEAD,则为HEAD),而没有请求体。如果定义了Request.GetBody函数,则307或308重定向将保留原始的HTTP方法和Body。 NewRequest函数自动为常见的标准库Body类型设置GetBody。 返回的任何错误均为*url.Error类型。如果请求超时或被取消,则url.Error值的Timeout方法将报告true。 func (*Client) Get func (c *Client) Get(url string) (resp *Response, err error) Get将GET发送到指定的URL。如果响应是以下重定向代码之一,则Get在调用客户端的CheckRedirect函数后执行重定向: 301 (Moved Permanently) 302 (Found) 303 (See Other) 307 (Temporary Redirect) 308 (Permanent Redirect) 如果客户端的CheckRedirect函数失败或存在HTTP协议错误,则返回错误。 非2xx响应不会导致错误。 返回的任何错误均为*url.Error类型。 如果请求超时或被取消,则url.Error值的Timeout方法将报告true。 当err为nil时,resp始终包含非nil的 resp.Body 。调用者完成读取后,应关闭resp.Body。 要使用自定义Header发出请求,请使用NewRequest和Client.Do。 func (*Client) Head func (c *Client) Head(url string) (resp *Response, err error) Head向指定的URL发出HEAD。如果响应是以下重定向代码之一,则Head在调用客户端的CheckRedirect函数后执行重定向: 301 (Moved Permanently) 302 (Found) 303 (See Other) 307 (Temporary Redirect) 308 (Permanent Redirect) func (*Client) Post func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error) Post发布POST到指定的URL。 调用者完成读取后,应关闭resp.Body。 如果提供的body是io.Closer,则在请求后将其关闭。 若要设置自定义Header,请使用NewRequest和Client.Do。 有关如何处理重定向的详细信息,请参阅Client.Do方法文档。 func (*Client) PostForm func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) PostForm向指定的URL发出POST,并将数据的键和值URL编码为请求体。 Content-TypeHeader设置为application/x-www-form-urlencoded。 若要设置其他Header,请使用NewRequest和Client.Do。 当err为nil时,resp始终包含非nil resp.Body,调用者完成读取后,应关闭resp.Body。 有关如何处理重定向的详细信息,请参阅Client.Do方法文档。 type CloseNotifier type CloseNotifier interface { // 当客户端连接断开时,CloseNotify返回一个通道,该通道最多接收单个值(true)。 // 在完全读取Request.Body之前,CloseNotify可能会等待通知。 // handler返回后,不能保证该通道会收到一个值。 // 如果协议是HTTP/1.1,并且在使用HTTP/1.1管道处理幂等请求(例如GET)时调用了CloseNotify,则后续管道请求的到来可能会导致在返回的通道上发送值。 // 实际上,HTTP/1.1管道未在浏览器中启用,并且很不常见。 如果这是一个问题,请使用HTTP/2或仅对诸如POST之类的方法使用CloseNotify。 CloseNotify() <-chan bool } type ConnState type ConnState int ConnState表示客户端与服务器的连接状态。由可选的Server.ConnState挂钩使用。 const ( // StateNew表示一个新连接,该连接应立即发送请求。 连接从此状态开始,然后过渡到StateActive或StateClosed。 StateNew ConnState = iota // StateActive表示已读取一个或多个请求字节的连接。 StateActive的Server.ConnState钩子在请求进入handler之前触发,直到请求被处理后才再次触发。 // 处理请求后,状态将转换为StateClosed,StateHijacked或StateIdle。 对于HTTP / 2,StateActive在从零到一个活动请求的转换上触发,并且仅在所有活动请求完成后才转换。 // 这意味着ConnState不能用于执行每个请求的预处理工作; ConnState仅记录连接的整体状态。 StateActive // StateIdle表示已完成处理请求并处于keep-alive状态的连接,正在等待新请求。 连接从StateIdle转换为StateActive或StateClosed。 StateIdle // StateHijacked 表示被劫持的连接, 这是状态的终态,它不会过渡到StateClosed。 StateHijacked // StateClosed表示已关闭的连接。 这是状态的终态, 被劫持的连接不会过渡到StateClosed。 StateClosed ) func (ConnState) String func (c ConnState) String() string type Cookie type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool SameSite SameSite Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } Cookie代表在HTTP响应的Set-CookieHeader或HTTP请求的CookieHeader中发送的HTTP Cookie,更多详情看这里。 func (*Cookie) String func (c *Cookie) String() string String返回用于Cookie头(如果仅设置了Name和Value)或Set-Cookie响应头(如果设置了其他字段)的cookie的序列化。如果c为nil或c.Name无效,则返回空字符串。 type CookieJar type CookieJar interface { // SetCookies在给定URL的回复中处理cookie的接收。 // 它可能会或可能不会选择保存cookie,具体取决于jar的策略和实现。 SetCookies(u *url.URL, cookies []*Cookie) // Cookies返回cookie,以发送对给定URL的请求。 // 具体实现取决于标准的cookie使用限制,例如RFC 6265。 Cookies(u *url.URL) []*Cookie } CookieJar管理HTTP请求中cookie的存储和使用。 CookieJar的实现必须安全,可以被多个goroutine并发使用。 net/http/cookiejar软件包提供了CookieJar实现。 type Dir type Dir string Dir使用限于特定目录树的原生文件系统来实现FileSystem。 尽管FileSystem.Open方法采用'/'分隔的路径,但Dir的字符串值是原生文件系统上的文件名,而不是URL,因此它由filepath.Separator分隔,不一定是'/'。 请注意,Dir将允许以句点开头(隐藏文件)的文件和目录访问,这可能会公开敏感目录(如.git目录)或敏感文件(如.htpasswd)。 要排除隐藏文件,请从服务器中删除文件/目录或创建自定义FileSystem实现。 空目录将被视为“.”。 func (Dir) Open func (d Dir) Open(name string) (File, error) Open使用os.Open实现FileSystem,打开文件以读取root以及相对于目录d的文件。 type File type File interface { io.Closer io.Reader io.Seeker Readdir(count int) ([]os.FileInfo, error) Stat() (os.FileInfo, error) } File由FileSystem的Open方法返回,并且可以由FileServer实现提供服务。 这些方法的行为应与*os.File上的行为相同。 type FileSystem type FileSystem interface { Open(name string) (File, error) } FileSystem实现对命名文件集合的访问。无论主机操作系统的约定如何,文件路径中的元素都用斜杠('/',U+002F)字符分隔。 type Flusher type Flusher interface { // Flush 刷新会将所有缓冲的数据发送到客户端。 Flush() } Flusher接口由ResponseWriters实现,它允许HTTPhandler将缓冲的数据刷新到客户端。 默认的HTTP/1.x和HTTP/2 ResponseWriter实现支持Flusher,但ResponseWriter包装器可能不支持。 handler应始终在运行时测试此功能。 请注意,即使对于支持Flush的ResponseWriters,如果客户端通过HTTP代理连接,在响应完成之前,缓冲的数据也可能无法到达客户端。 type Handler type Handler interface { ServeHTTP(ResponseWriter, *Request) } Handler响应HTTP请求。 ServeHTTP应将响应Header和数据写入ResponseWriter,然后返回。返回信号表明请求已完成;在ServeHTTP调用完成后或与之同时使用ResponseWriter或从Request.Body中读取是无效的。 根据HTTP客户端软件,HTTP协议版本以及客户端和Go服务器之间的任何中介,可能无法在写入ResponseWriter之后从Request.Body中读取。谨慎的handler应先读取Request.Body,然后再进行回复。 除读取Body外,handler不应修改提供的请求。 如果出现ServeHTTP出现运行时恐慌(painc),则服务端(ServeHTTP的调用方)将假定panic的影响与处于活跃状态的请求无关。它将会恢复panic,将堆栈跟踪记录到服务器错误日志中,然后关闭网络连接或发送HTTP/2 RST_STREAM,具体取决于HTTP协议。要中止handler,以便客户端看到中断的响应,而服务器不会记录错误,那么panic应该带有ErrAbortHandler值。 func FileServer func FileServer(root FileSystem) Handler FileServer返回一个handler,该handler以根目录为根文件系统内容为HTTP请求提供服务。 要使用操作系统的文件系统实现,请使用http.Dir: http.Handle("/", http.FileServer(http.Dir("/tmp"))) 作为一种特殊情况,返回的文件服务器会将以“/index.html”结尾的所有请求重定向到同一路径,而没有最终的“index.html”。 Example // 简单的静态Web服务器 log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/usr/share/doc")))) Example(DotFileHiding) package http_test import ( "log" "net/http" "os" "strings" ) // containsDotFile报告name是否包含以句点开头的path元素。 // 假定name由正斜杠分隔,由http.FileSystem接口保证。 func containsDotFile(name string) bool { parts := strings.Split(name, "/") for _, part := range parts { if strings.HasPrefix(part, ".") { return true } } return false } // dotFileHidingFile是dotFileHidingFileSystem中的http.File使用。 // 它用于包装http.File的Readdir方法,以便我们可以从其输出中删除以句点开头的文件和目录。 type dotFileHidingFile struct { http.File } // Readdir是嵌入式File的Readdir方法的包装,可过滤掉名称中以句点开头的所有文件。 func (f dotFileHidingFile) Readdir(n int) (fis []os.FileInfo, err error) { files, err := f.File.Readdir(n) for _, file := range files { // 过滤点文件 if !strings.HasPrefix(file.Name(), ".") { fis = append(fis, file) } } return } // dotFileHidingFileSystem是一个http.FileSystem,可隐藏隐藏的“点文件”,使其不再提供服务。 type dotFileHidingFileSystem struct { http.FileSystem } // Open是嵌入式FileSystem的Open方法的包装, // 当name具有名称以其路径开头的文件或目录时,它将包装403权限错误。 func (fs dotFileHidingFileSystem) Open(name string) (http.File, error) { if containsDotFile(name) { // 如果是点文件, 返回 403 return nil, os.ErrPermission } file, err := fs.FileSystem.Open(name) if err != nil { return nil, err } return dotFileHidingFile{file}, err } func ExampleFileServer_dotFileHiding() { fs := dotFileHidingFileSystem{http.Dir(".")} http.Handle("/", http.FileServer(fs)) log.Fatal(http.ListenAndServe(":8080", nil)) } func NotFoundHandler func NotFoundHandler() Handler NotFoundHandler返回一个简单的handler,该handler以“404页面未找到”答复来回复每个请求。 Example(NotFoundHandler) mux := http.NewServeMux() // 创建示例handler以返回404 mux.Handle("/resources", http.NotFoundHandler()) // 创建示例handler以返回200 mux.Handle("/resources/people/", newPeopleHandler()) log.Fatal(http.ListenAndServe(":8080", mux)) func RedirectHandler func RedirectHandler(url string, code int) Handler RedirectHandler返回一个handler,该handler使用给定的状态码将收到的每个请求重定向到给定的url。 提供的代码应在3xx范围内,通常为StatusMovedPermanently,StatusFound或StatusSeeOther。 func StripPrefix func StripPrefix(prefix string, h Handler) Handler StripPrefix通过从请求URL的路径中删除给定前缀并调用handler h,返回处理HTTP请求的handler。 StripPrefix通过回复HTTP 404 not found错误来处理不以前缀开头的路径的请求。 Example(StripPrefix) // 要在备用URL路径(/tmpfiles/)下为磁盘(/tmp)上的目录提供服务,请在FileServer看到之前使用StripPrefix修改请求URL的路径: http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp")))) func TimeoutHandler func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler TimeoutHandler返回一个在给定时间限制下运行h的Handler。 新的handler调用h.ServeHTTP来处理每个请求,但是如果调用的运行时间超过其时间限制,则该handler将以503 Service Unavailable错误和响应体中的给定消息作为响应。 (如果msg为空,则将发送适当的默认消息。)在这样的超时之后,用h对其ResponseWriter进行写操作将返回ErrHandlerTimeout。 TimeoutHandler支持Flusher和Pusher接口,但不支持Hijacker接口。 type HandlerFunc type HandlerFunc func(ResponseWriter, *Request) HandlerFunc类型是一个适配器,允许将普通函数用作HTTP处理程序。如果f是具有适当签名的函数,则HandlerFunc(f) 是调用f的处理程序。 func (HandlerFunc) ServeHTTP func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) ServeHTTP 调用 f(w, r)。 type Header type Header map[string][]string Header代表HTTPHeader中的键/值对。 key应采用CanonicalHeaderKey返回的规范形式。 func (Header) Add func (h Header) Add(key, value string) Add将键值对添加到Header。它附加到与键关联的任何现有值。key不区分大小写;它由CanonicalHeaderKey规范化。 func (Header) Clone func (h Header) Clone() Header 如果h为nil,则Clone返回h或nil的副本。 func (Header) Del func (h Header) Del(key string) Del删除与键关联的值。key不区分大小写;它由CanonicalHeaderKey规范化。 func (Header) Get func (h Header) Get(key string) string Get获取与给定键关联的第一个值。 如果没有与键关联的值,则Get返回""。 不区分大小写; textproto.CanonicalMIMEHeaderKey用于规范化提供的key。 要访问键的多个值或使用非规范键,请直接访问map。 func (Header) Set func (h Header) Set(key, value string) Set将与key关联的header条目设置为单个元素值。 它替换了与键关联的任何现有值。 key不区分大小写; 它由textproto.CanonicalMIMEHeaderKey规范化。 要使用非规范键,请直接分配给map。 func (Header) Write func (h Header) Write(w io.Writer) error Write以传输格式写header。 func (Header) WriteSubset func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error WriteSubset以传输格式写入header。如果exclude不为nil,则不会写入exclude [key] == true的键。 type Hijacker type Hijacker interface { // Hijack使调用者可以接管连接。 // 调用Hijack之后,HTTP服务器库将不会对该连接执行任何其他操作。 // 管理和关闭连接成为调用者的责任。 // 根据服务器的配置,返回的net.Conn可能已设置了读取或写入的期限。 // 调用者有责任根据需要设置或清除这些截止时间。 // 返回的bufio.Reader可能包含来自客户端的未处理的缓冲数据。 // 调用Hijack之后,不得使用原始的Request.Body。 // 原始请求的context仍然有效,并且直到该请求的ServeHTTP方法返回后才被取消。 Hijack() (net.Conn, *bufio.ReadWriter, error) } Hijacker接口是由ResponseWriters实现的,它允许HTTP hander接管连接。 HTTP/1.x连接的默认ResponseWriter支持Hijacker,但HTTP/2连接有意设置为不支持。 ResponseWriter包装器也可能不支持Hijacker。 handler应始终在运行时测试此功能。 Example(Hijacker) http.HandleFunc("/hijack", func(w http.ResponseWriter, r *http.Request) { hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) return } conn, bufrw, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // 不要忘记关闭连接 defer conn.Close() bufrw.WriteString("Now we're speaking raw TCP. Say hi: ") bufrw.Flush() s, err := bufrw.ReadString('\n') if err != nil { log.Printf("error reading string: %v", err) return } fmt.Fprintf(bufrw, "You said: %q\nBye.\n", s) bufrw.Flush() }) type PushOptions type PushOptions struct { // Method为承诺的请求指定HTTP方法。 // 如果设置,则必须为“ GET”或“ HEAD”。空表示“ GET”。 Method string // Header指定其他承诺的请求Header。 // 这不能包括HTTP/2伪Header字段,例如“:path”和“:scheme”,它们会自动添加。 Header Header } PushOptions描述了Pusher.Push的选项。 type Pusher type Pusher interface { // Push启动HTTP/2服务器来推送。 这将使用给定的目标和选项构造一个综合请求, // 将该请求序列化为PUSH_PROMISE帧,然后使用服务器的handler分派该请求。 // 如果opts为nil,则使用默认选项。 // target必须是绝对路径(例如“ /path”)或包含有效host和与父请求相同的scheme的绝对URL。 // 如果目标是路径,它将继承父请求的scheme和host。 // HTTP/2规范不允许递归推送和交叉授权推送。 // 推送可能会或可能不会检测到这些无效的推送; 但是,合格的客户端将检测并取消无效的推送。 // 希望推送URL X的handler应在发送任何可能触发URL X请求的数据之前调用Push。 // 这避免了客户端在收到X的PUSH_PROMISE之前发出X请求的竞争。 // Push将在单独的goroutine中运行,从而使到达顺序不确定。 调用者需要实现任何所需的同步。 // 如果客户端禁用了Push或底层连接不支持Push,则Push返回ErrNotSupported。 Push(target string, opts *PushOptions) error } Pusher是由ResponseWriters实现的支持HTTP/2服务器推送的接口。有关更多背景信息,请参见这里。 type Request type Request struct { // Method指定HTTP方法(GET,POST,PUT等)。 // 对于客户端请求,空字符串表示GET。 // Go的HTTP客户端不支持使用CONNECT方法发送请求。 // 有关详细信息,请参见Transport文档。 Method string // URL指定要请求的URI(对于服务端请求)或要访问的URL(对于客户端请求)。 // 对于服务端请求,将从存储在RequestURI中的请求行上提供的URI解析URL。 // 对于大多数请求,Path和RawQuery以外的其他字段将为空。 (请参阅RFC 7230,第5.3节) // 对于客户端请求,URL的host指定要连接的服务器, // 而请求的host字段则可选地指定要在HTTP请求中发送的hostHeader值。 URL *url.URL // 传入服务器请求的协议版本。 // 对于客户请求,将忽略这些字段。HTTP客户端代码始终使用HTTP/1.1或HTTP/2。 // 有关详细信息,请参见Transport文档。 Proto string // "HTTP/1.0" ProtoMajor int // 1 ProtoMinor int // 0 // Header包含服务端接收或客户端发送的请求Header字段。 // 如果服务端收到带有Header行的请求: // Host: example.com // accept-encoding: gzip, deflate // Accept-Language: en-us // fOO: Bar // foo: two // Header = map[string][]string{ // "Accept-Encoding": {"gzip, deflate"}, // "Accept-Language": {"en-us"}, // "Foo": {"Bar", "two"}, // } // 对于传入的请求,Host Header被提升为Request.Host字段并从 Header映射中删除。 // HTTP定义Header名称不区分大小写。 请求解析器通过使用CanonicalHeaderKey来实现此目的, // 使第一个字符以及连字符后的所有字符都变为大写,其余的都变为小写。 // 对于客户端请求,某些header(例如Content-Length和Connection)会在需要时自动写入, // 并且Header中的值可能会被忽略。 请参阅文档中的Request.Write方法。 Header Header // Body 是请求体。 // 对于客户端请求,nil body表示该请求没有请求体,例如GET请求。 // HTTP客户端的transport负责调用Close方法。 // 对于服务端请求,请求体始终为non-nil,但在不存在请求体时将立即返回EOF。 // 服务端将关闭请求体。 ServeHTTP handler不需要这么做。 Body io.ReadCloser // GetBody定义了一个可选的func来返回Body的新副本。 // 它用于当客户端请求重定向需要多次读取Body时。使用GetBody仍然需要设置Body。 // 对于服务端请求,它是不使用的。 GetBody func() (io.ReadCloser, error) // ContentLength记录关联内容的长度。 // 值-1表示长度未知。 // 值>=0表示可以从请求体读取给定的字节数。 // 对于客户请求,non-nil Body 的值为0也会被认为是未知。 ContentLength int64 // TransferEncoding列出从最外层到最内层的传输编码。 // 空列表表示“identity”编码。 通常可以忽略TransferEncoding。 // 发送和接收请求时,将根据需要自动添加和删除分块编码。 TransferEncoding []string // Close 指示是在回复此请求后(对于服务器)还是在发送此请求并读取其响应(对于客户端)之后关闭连接。 // 对于服务端请求,HTTP服务器会自动处理此请求,并且处理程序不需要此字段。 // 对于客户端请求,设置此字段可防止在相同主机的请求之间重复使用TCP连接, // 就像设置了Transport.DisableKeepAlives一样。 Close bool // 对于服务器请求,Host指定在其上搜索URL的host。 // 根据RFC 7230,第5.4节,这是“host”Header的值或URL本身中提供的主机名。 // 它的形式可能是“ host:port”。 对于国际域名,Host可以采用Punycode或Unicode形式。 // 如果需要,请使用golang.org/x/net/idna将其转换为两种格式。 // 为了防止DNS重新绑定攻击,服务器handler应验证主机Header是否具有其认为自己具有权威性的值。 // 随附的ServeMux支持注册到特定host名的模式,从而保护其注册的handler。 // 对于客户端请求,host可以选择覆盖要发送的主机头。 如果为空,则Request.Write方法使用URL.Host的值。 // 主机可能包含国际域名。 Host string // 表单包含已解析的表单数据,包括URL字段的查询参数和PATCH,POST或PUT表单数据。 // 该字段仅在调用ParseForm之后可用。 HTTP客户端会忽略Form,而使用Body。 Form url.Values // PostForm包含从PATCH,POST或PUT Body参数解析的表单数据。 // 该字段仅在调用ParseForm之后可用。 HTTP客户端会忽略PostForm并改用Body。 PostForm url.Values // MultipartForm是已解析的多部分表单,包括文件上传。 // 仅在调用ParseMultipartForm之后,此字段才可用。 HTTP客户端会忽略MultipartForm并改用Body。 MultipartForm *multipart.Form // Trailer指定在请求体之后发送的其他Header。 // 对于服务器请求,Trailer map 最初仅包含 Trailer 键,其值为nil。 // (客户端声明它将稍后发送的Trailer。)handler从Body读取时,它不得引用 Trailer。 // 从Body读取返回EOF后,Trailer可以再次读取,并且包含非null值(如果它们是由客户端发送的)。 // 对于客户端请求,必须将Trailer初始化为包含Trailer key 的 map,以便以后发送。 // 这些值可以为nil或它们的最终值。 ContentLength必须为0或-1,才能发送分块的请求。 // 发送HTTP请求后,可以在读取请求体的同时更新map值。 一旦Body返回EOF,调用方就不得使Trailer发生改变。 // 很少有HTTP客户端,服务器或代理支持HTTP Trailer。 Trailer Header // RemoteAddr允许HTTP服务器和其他软件记录发送请求的网络地址,通常用于日志记录。 // ReadRequest不会填写此字段,并且没有定义的格式。 // 在调用handler之前,此程序包中的HTTP服务器将RemoteAddr设置为“ IP:Port”地址。 HTTP客户端将忽略此字段。 RemoteAddr string // RequestURI是客户端发送到服务器的请求行(RFC 7230,第3.1.1节)的未经修改的请求目标。 // 通常应改用URL字段。 在HTTP客户端请求中设置此字段是错误的。 RequestURI string // TLS允许HTTP服务器和其他软件记录有关在其上接收到请求的TLS连接的信息。ReadRequest不会填写此字段。 // 此程序包中的HTTP服务器在调用handler之前为启用TLS的连接设置字段。 // 否则,该字段将为零。 HTTP客户端会忽略此字段。 TLS *tls.ConnectionState // Cancel是一个可选通道,当它关闭则表示客户端的请求应被视为已取消。 // 并非RoundTripper的所有实现都支持取消。 // 对于服务器请求,此字段不适用。 // 弃用:而是使用NewRequestWithContext设置请求的context。 // 如果同时设置了请求的“cancel”字段和context,则不确定是否遵守“cancel”。 Cancel <-chan struct{} // Response是导致创建此请求的重定向响应。仅在客户端重定向期间填充此字段。 Response *Response } Request表示服务器接收或客户端发送的HTTP请求。 客户端和服务器使用情况之间的字段语义略有不同。 除了以下字段上的注释外,请参阅Request.Write和RoundTripper的文档。 func NewRequest func NewRequest(method, url string, body io.Reader) (*Request, error) NewRequest使用background context包装NewRequestWithContext。 func NewRequestWithContext func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error) 给定Method,URL和可选Body,NewRequestWithContext返回一个新的请求。 如果提供的body同时也是io.Closer,则返回的Request.Body设置为body,并且将通过客户端方法Do,Post和PostForm以及Transport.RoundTrip关闭。 NewRequestWithContext返回适合与Client.Do或Transport.RoundTrip一起使用的请求。若要创建用于测试服务器handler的请求,请使用net/http/httptest程序包中的NewRequest函数,使用ReadRequest,或手动更新Request字段。对于传出的客户端请求,context控制请求的整个生命周期及其响应:获取连接,发送请求以及读取响应Header和Body。有关入站和出站请求字段之间的区别,请参见Request type的文档。 如果body的类型为*bytes.Buffer,*bytes.Reader或*strings.Reader,则返回的请求的ContentLength设置为其确切值(而不是-1),将填充GetBody(因此307和308重定向可以重播body),如果ContentLength为0,则将Body设置为NoBody。 func ReadRequest func ReadRequest(b *bufio.Reader) (*Request, error) ReadRequest读取并解析来自b的传入请求。 ReadRequest是一个底层功能,仅应用于专业应用程序。大多数代码应使用服务器读取请求并通过Handler接口处理请求。 ReadRequest仅支持HTTP/1.x请求。 对于HTTP/2,请使用golang.org/x/net/http2。 func (*Request) AddCookie func (r *Request) AddCookie(c *Cookie) AddCookie将cookie添加到请求中。根据RFC 6265第5.4节,AddCookie不会附加多个Cookie header字段。这意味着所有cookie(如果有的话)都写在同一行中,并用分号分隔。 func (*Request) BasicAuth func (r *Request) BasicAuth() (username, password string, ok bool) 如果请求使用HTTP基本认证,则BasicAuth返回请求的授权header中提供的用户名和密码。请参阅RFC 2617,第2节。 func (*Request) Clone func (r *Request) Clone(ctx context.Context) *Request Clone 返回r的深层副本,其context更改为ctx。 提供的ctx必须为非零。 对于传出的客户端请求,context控制请求的整个生命周期及其响应:获取连接,发送请求以及读取响应header和body。 func (*Request) Context func (r *Request) Context() context.Context Context返回请求的context。 若要更改context,请使用WithContext。 返回的context始终为非零; 它默认为 background context。 对于传出的客户端请求,context控制取消。 对于传入的服务器请求,当客户端的连接关闭,请求被取消(使用HTTP/2)或ServeHTTP方法返回时,context将被取消。 func (*Request) Cookie func (r *Request) Cookie(name string) (*Cookie, error) Cookie返回请求中提供的命名cookie,如果未找到,则返回ErrNoCookie。如果多个Cookie与给定名称匹配,则仅返回一个Cookie。 func (*Request) Cookies func (r *Request) Cookies() []*Cookie Cookies解析并返回与请求一起发送的HTTP cookie。 func (*Request) FormFile func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) FormFile返回提供的表单key的第一个文件。如果需要,FormFile调用ParseMultipartForm和ParseForm。 func (*Request) FormValue func (r *Request) FormValue(key string) string FormValue返回查询的命名组件的第一个值。 POST和PUT请求体的参数优先于URL查询字符串值。 FormValue在必要时调用ParseMultipartForm和ParseForm,并忽略这些函数返回的任何错误。 如果key不存在,则FormValue返回空字符串。 要访问同一key的多个值,请调用ParseForm,然后直接检查Request.Form。 func (*Request) MultipartReader func (r *Request) MultipartReader() (*multipart.Reader, error) 如果这是multipart/form-data或multipart/mixedPOST请求,则MultipartReader返回MIME分段阅读器,否则返回nil和错误。使用此函数代替ParseMultipartForm将请求体作为流处理。 func (*Request) ParseForm func (r *Request) ParseForm() error ParseForm填充r.Form和r.PostForm。 对于所有请求,ParseForm都会从URL解析原始查询并更新r.Form。 对于POST,PUT和PATCH请求,它还将请求体解析为一种形式,并将结果放入r.PostForm和r.Form中。 请求体参数优先于r.Form中的URL查询字符串值。 对于其他HTTP方法,或者当Content-Type不是application/x-www-form-urlencoded时,不会读取请求体,并且r.PostForm初始化为非null的空值。 如果请求体的大小尚未受到MaxBytesReader的限制,则大小上限为10MB。 ParseMultipartForm自动调用ParseForm。 ParseForm是幂等的。 func (*Request) ParseMultipartForm func (r *Request) ParseMultipartForm(maxMemory int64) error ParseMultipartForm将请求体解析为multipart/form-data。 整个请求体将被解析,其文件部分的总计maxMemory字节最多存储在内存中,其余部分存储在磁盘上的临时文件中。 如果需要,ParseMultipartForm调用ParseForm。 一次调用ParseMultipartForm之后,后续调用无效。 func (*Request) PostFormValue func (r *Request) PostFormValue(key string) string PostFormValue返回POST,PATCH或PUT请求体的命名组件的第一个值。 URL查询参数将被忽略。 如果需要,PostFormValue调用ParseMultipartForm和ParseForm,并忽略这些函数返回的任何错误。 如果键不存在,则PostFormValue返回空字符串。 func (*Request) ProtoAtLeast func (r *Request) ProtoAtLeast(major, minor int) bool ProtoAtLeast报告请求中使用的HTTP协议是否至少为major.minor。 func (*Request) Referer func (r *Request) Referer() string 如果请求中发送了Referer,则返回Referering URL。 Referer来源网址拼写错误,就像请求本身一样,这是HTTP最早的错误。 该值也可以从Header map中提取为Header [“Referer”]; 将其作为方法使用的好处是,编译器可以诊断使用备用(正确的英语)拼写req.Referrer()的程序,但不能诊断使用Header [“Referrer”]的程序。 func (*Request) SetBasicAuth func (r *Request) SetBasicAuth(username, password string) SetBasicAuth将请求的Authorization header设置为使用HTTP基本身份验证以及提供的用户名和密码。 使用HTTP基本认证时,提供的用户名和密码未加密。 某些协议可能会对预转义用户名和密码提出其他要求。 例如,当与OAuth2一起使用时,两个参数都必须首先使用url.QueryEscape进行URL编码。 func (*Request) UserAgent func (r *Request) UserAgent() string 如果在请求中发送了UserAgent,则返回客户端的User-Agent。 func (*Request) WithContext func (r *Request) WithContext(ctx context.Context) *Request WithContext返回r的浅表副本,其context更改为ctx。 提供的ctx必须为非零。 对于传出的客户端请求,context控制请求的整个生命周期及其响应:获取连接,发送请求以及读取响应头和响应体。 要使用context创建新请求,请使用NewRequestWithContext。 要更改请求(例如传入)的context,您还需要修改以发送出去,请使用Request.Clone。 在这两种用途之间,很少需要WithContext。 func (*Request) Write func (r *Request) Write(w io.Writer) error Write以传输格式写入HTTP/1.1请求,即请求头和请求体。此方法查询请求的以下字段: Host URL Method (defaults to "GET") Header ContentLength TransferEncoding Body 如果存在请求体,则Content-Length为<= 0,并且TransferEncoding尚未设置为“identity”,Write将“ Transfer-Encoding: chunked”添加到请求头,发送后将其关闭。 func (*Request) WriteProxy func (r *Request) WriteProxy(w io.Writer) error WriteProxy类似于Write,但是以HTTP代理期望的形式写入请求。 特别是,WriteProxy根据RFC 7230的5.3节(包括scheme和host)用绝对URI写入请求的初始Request-URI行。无论哪种情况,WriteProxy都会使用r.Host或r.URL.Host写入Host header。 type Response type Response struct { Status string // e.g. "200 OK" StatusCode int // e.g. 200 Proto string // e.g. "HTTP/1.0" ProtoMajor int // e.g. 1 ProtoMinor int // e.g. 0 // Header将header key映射到value。 // 如果响应中的多个header具有相同的键,则可以使用逗号分隔符将它们连接在一起。 // (RFC 7230第3.2.2节要求,多个header在语义上等效于逗号分隔的序列。) // 当header值被该结构中的其他字段(例如ContentLength,TransferEncoding,Trailer)复制时, // 这些字段值是权威的。 // map中的key已规范化(请参见CanonicalHeaderKey)。 Header Header // Body代表响应体。 // 在读取“body”字段时,将按需流式传输响应体。 如果网络连接失败或服务器终止响应,则Body.Read调用将返回错误。 // http 的Client 和Transport 保证即使在没有响应体的响应或长度为零的响应中,响应体也始终为非零。 // 关闭响应体是调用者的责任。 如果未读取并关闭响应体,则默认的HTTP客户端的传输可能不会重用HTTP/1.x“keep-alive” TCP连接。 // 如果服务器回复了“分块”传输编码,则响应体将自动分块。 // 从Go 1.12开始,Body还将在成功的“101交换协议”响应上实现io.Writer, // 该响应由WebSocket和HTTP/2的“h2c”模式使用。 Body io.ReadCloser // ContentLength记录关联内容的长度。 值-1表示长度未知。 // 除非Request.Method为“HEAD”,否则值>=0表示可以从Body中读取给定的字节数。 ContentLength int64 // 包含从最外部到最内部的传输编码。 值为nil,表示使用“identity”编码,即不进行编码。 TransferEncoding []string // Close记录在读取响应体后,header是否指示关闭连接。 该值是给客户的建议:ReadResponse和Response.Write都不会关闭连接。 Close bool // Uncompressed报告响应是否已压缩发送,并已被http包解压缩。 // 如果为true,则从Body读取将产生未压缩的内容,而不是从服务器实际设置的压缩内容, // ContentLength设置为-1,并且从responseHeader中删除“Content-Length”和“Content-Encoding”字段。 // 要从服务器获取原始响应,请将Transport.DisableCompression设置为true。 Uncompressed bool // Trailer将trailer键映射到与header相同格式的值。 // Trailer最初仅包含nil值,服务器“Trailer”header值中指定的每个键对应一个值。这些值不会添加到Header中。 // 不得在响应体上与Read调用同时访问Trailer。 在Body.Read返回io.EOF之后,Trailer将包含服务器发送的所有trailer值。 Trailer Header // Request是为获取此响应而发送的请求。 请求体为零(已被消耗)。 仅针对客户端请求填充。 Request *Request // TLS包含有关在其上接收到响应的TLS连接的信息。 对于未加密的响应,它为nil。 // 指针在响应之间共享,不应修改。 TLS *tls.ConnectionState } 响应表示来自HTTP请求的响应。 一旦收到响应头,Client和Transport将从服务器返回响应。在读取“Body”字段时,将按需流式传输响应体。 func Get func Get(url string) (resp *Response, err error) Get将GET发送到指定的URL。如果响应是以下重定向代码之一,则Get将遵循该重定向,最多10个重定向: 301 (Moved Permanently) 302 (Found) 303 (See Other) 307 (Temporary Redirect) 308 (Permanent Redirect) 如果重定向太多或HTTP协议错误,则返回错误。 非2xx响应不会导致错误。 返回的任何错误均为*url.Error类型。 如果请求超时或被取消,则url.Error值的Timeout方法将报告true。 当err为nil时,resp始终包含一个非nil resp.Body。 调用者完成读取后,应关闭resp.Body。 Get是DefaultClient.Get的包装。 要使用自定义header发出请求,请使用NewRequest和DefaultClient.Do。 Example(Get) res, err := http.Get("http://www.google.com/robots.txt") if err != nil { log.Fatal(err) } robots, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) } fmt.Printf("%s", robots) func Head func Head(url string) (resp *Response, err error) Head向指定的URL发出HEAD。如果响应是以下重定向代码之一,则Head遵循该重定向,最多10个重定向: 301 (Moved Permanently) 302 (Found) 303 (See Other) 307 (Temporary Redirect) 308 (Permanent Redirect) Head是DefaultClient.Head的包装器。 func Post func Post(url, contentType string, body io.Reader) (resp *Response, err error) Post发布POST到指定的URL。 调用者完成读取后,应关闭resp.Body。 如果提供的body是io.Closer,则在请求后将其关闭。 Post是DefaultClient.Post的包装。 要设置自定义header,请使用NewRequest和DefaultClient.Do。 有关如何处理重定向的详细信息,请参阅Client.Do方法文档。 func PostForm func PostForm(url string, data url.Values) (resp *Response, err error) PostForm向指定的URL发出POST,并将数据的键和值URL编码为请求体。 Content-Type header设置为application/x-www-form-urlencoded。 要设置其他header,请使用NewRequest和DefaultClient.Do。 当err为nil时,resp始终包含一个非nil resp.Body。 调用者完成读取后,应关闭resp.Body。 PostForm是DefaultClient.PostForm的包装。 有关如何处理重定向的详细信息,请参阅Client.Do方法文档。 func ReadResponse func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) ReadResponse从r读取并返回HTTP响应。 req参数可选地指定与此响应相对应的请求。 如果为零,则假定为GET请求。 读取完resp.Body后,客户端必须调用resp.Body.Close。 调用之后,客户端可以检查trailer,以查找响应tailer中包含的键/值对。 func (*Response) Cookies func (r *Response) Cookies() []*Cookie Cookies解析并返回Set-Cookie header中设置的cookie。 func (*Response) Location func (r *Response) Location() (*url.URL, error) Location返回响应的“location”header(如果存在)的URL。相对重定向是相对于响应的请求来解决的。如果不存在Location header,则返回ErrNoLocation。 func (*Response) ProtoAtLeast func (r *Response) ProtoAtLeast(major, minor int) bool ProtoAtLeast报告响应中使用的HTTP协议是否至少为major.minor。 func (*Response) Write func (r *Response) Write(w io.Writer) error Write以HTTP/1.x服务器响应格式将r写入w,包括状态行,header,body和可选的trailer。 此方法查询响应r的以下字段: StatusCode ProtoMajor ProtoMinor Request.Method TransferEncoding Trailer Body ContentLength Header, values for non-canonical keys will have unpredictable behavior 发送后,响应体将关闭。 type ResponseWriter type ResponseWriter interface { // Header返回将由WriteHeader发送的header map。header map也是handler可以用来设置HTTP trailer的机制。 // 除非修改后的header是trailer,否则在调用WriteHeader(或Write)后更改header map无效。 // 设置trailer有两种方法。 首选方法是在header中预先声明稍后将发送的trailer, // 方法是将“Trailer”header设置为稍后将出现的键的名称。 // 在这种情况下,Header映射的那些键被视为trailer。参见示例。 // 第二种方法是,对于直到第一次处理之后才被handler所知的trailer键, // 在Header映射键之前加上TrailerPrefix常量值。 请参阅TrailerPrefix。 // 要取消自动响应header(例如“Date”),请设置它们的值为nil。 Header() Header // Write将数据作为HTTP回复的一部分写入连接。 // 如果尚未调用WriteHeader,则Write在写入数据之前会调用WriteHeader(http.StatusOK)。 // 如果header不包含Content-Type行,则Write将Content-Type集添加到将初始512字节的写入数据传递到DetectContentType的结果中。 // 此外,如果所有写入数据的总大小小于几KB,并且没有Flush调用,则会自动添加Content-Length header。 // 根据HTTP协议版本和客户端,调用Write或WriteHeader可能会阻止将来对Request.Body进行读取。 // 对于HTTP/1.x请求,handler应在写入响应之前读取所有需要的请求体数据。 // 刷新header后(由于显式的Flusher.Flush调用或写入足够的数据以触发刷新),请求体可能不可用。 // 对于HTTP/2请求,Go HTTP服务器允许handler在同时写入响应的同时继续读取请求体。 // 但是,并非所有的HTTP/2客户端都支持这种行为。 // 如果可能,handler应在写入之前先进行读取,以最大程度地实现兼容性。 Write([]byte) (int, error) // WriteHeader发送带有提供的状态代码的HTTP响应头。 如果未显式调用WriteHeader,则对Write的第一次调用将触发一个隐式WriteHeader(http.StatusOK)。 // 因此,对WriteHeader的显式调用主要用于发送错误代码。 提供的代码必须是有效的HTTP 1xx-5xx状态代码。 只能写入一个header。 // Go当前不支持发送用户定义的1xx信息性header,但服务器会在读取Request.Body时自动发送的100-xx响应头,但不支持发送该header。 WriteHeader(statusCode int) } HTTP handler使用ResponseWriter接口构造HTTP响应。 返回Handler.ServeHTTP方法后,不得使用ResponseWriter。 Example(Trailer) HTTP Trailer是一组键/值对,例如header,位于HTTP响应之后而不是之前。 mux := http.NewServeMux() mux.HandleFunc("/sendstrailers", func(w http.ResponseWriter, req *http.Request) { // 在对WriteHeader或Write的任何调用之前,声明将在HTTP响应期间设置的Trailer。 // 这三个header实际上是在Trailer中发送的。 w.Header().Set("Trailer", "AtEnd1, AtEnd2") w.Header().Add("Trailer", "AtEnd3") w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header w.WriteHeader(http.StatusOK) w.Header().Set("AtEnd1", "value 1") io.WriteString(w, "This HTTP response has both headers before this text and trailers at the end.\n") w.Header().Set("AtEnd2", "value 2") w.Header().Set("AtEnd3", "value 3") // These will appear as trailers. }) type RoundTripper type RoundTripper interface { // RoundTrip执行一个HTTP事务,为提供的请求返回响应。 // RoundTrip不应尝试解释响应。 // 特别是,如果RoundTrip获得响应,则必须返回err == nil, // 而不管响应的HTTP状态代码如何。如果失败,则应保留非null错误。 // 同样,RoundTrip不应尝试处理更高级别的协议详细信息,例如重定向,身份验证或cookie。 // 除了消费和关闭请求体之外,RoundTrip不应修改请求。 RoundTrip可以在单独的goroutine中读取请求的字段。 // 在响应体关闭之前,调用者不应更改或重用请求。 // RoundTrip必须要关闭响应体,包括发生错误时,但根据实现的不同, // 即使在RoundTrip返回之后,也可能在单独的goroutine中关闭它。 // 这意味着希望重用响应体以用于后续请求的调用者必须安排在等待Close调用之后再这样做。 // 请求的URL和Header字段必须初始化。 RoundTrip(*Request) (*Response, error) } RoundTripper是表示执行单个HTTP事务,获取给定请求的响应的能力的接口。RoundTripper必须安全,可以同时被多个goroutine使用。 var DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, ForceAttemptHTTP2: true, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } DefaultTransport是Transport的默认实现,由DefaultClient使用。 它根据需要建立网络连接,并缓存它们以供后续调用重用。 它按照$HTTP_PROXY和$NO_PROXY(或$http_proxy和$no_proxy)环境变量的指示使用HTTP代理。 func NewFileTransport func NewFileTransport(fs FileSystem) RoundTripper NewFileTransport返回一个新的RoundTripper,服务于提供的FileSystem。 返回的RoundTripper会忽略传入请求中的URL host以及该请求的大多数其他属性。 NewFileTransport的典型用例是在TRansport中注册“file”协议,如下所示: t := &http.Transport{} t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/"))) c := &http.Client{Transport: t} res, err := c.Get("file:///etc/passwd") ... type SameSite type SameSite int SameSite允许服务器定义cookie属性,从而使浏览器无法将cookie与跨站点请求一起发送。 主要目标是减轻跨域信息泄漏的风险,并提供针对跨站点请求伪造攻击的某种保护。 更多信息点击这里。 const ( SameSiteDefaultMode SameSite = iota + 1 SameSiteLaxMode SameSiteStrictMode SameSiteNoneMode ) type ServeMux type ServeMux struct { mu sync.RWMutex m map[string]muxEntry es []muxEntry // slice of entries sorted from longest to shortest. hosts bool // whether any patterns contain hostnames } ServeMux是一个HTTP请求多路复用器。它根据注册的模式列表将每个传入请求的URL匹配,并为与URL最匹配的模式调用处理程序。 模式命名固定的,有根的路径(例如“/favicon.ico”)或有根的子树(例如“/images/”)(请注意结尾的斜杠)。较长的模式优先于较短的模式,因此,如果同时为“/images/”和“/images/thumbnails/”注册了handler,则将为从“/images/thumbnails/”开始的路径调用后handler,将在“/images/”子树中接收对任何其他路径的请求。 请注意,由于以斜杠结尾的模式命名了一个有根的子树,因此模式“/”与所有其他已注册模式不匹配的路径匹配,而不仅仅是Path==“/”的URL。 如果已经注册了一个子树,并且接收到一个命名该子树根的请求而没有其后斜杠,则ServeMux将该请求重定向到该子树根(添加后斜杠)。可以用单独的路径注册来覆盖此行为,而不必使用斜杠。例如,注册“/images/”会使ServeMux将对“/images”的请求重定向到“/images/”,除非已单独注册了“/images”。 模式可以选择以主机名开头,仅将匹配项限制在该主机上。特定于主机的模式优先于常规模式,因​​此处理程序可以注册两个模式“/codesearch”和“codesearch.google.com/”,而不必同时接收对“http://www.google.com/”的请求”。 ServeMux还负责清理URL请求路径和Host header,清除端口号并重定向任何包含的请求.或..元素,或重复的斜杠表示为等效的,更简洁的URL。 func NewServeMux func NewServeMux() *ServeMux NewServeMux分配并返回一个新的ServeMux。 func (*ServeMux) Handle func (mux *ServeMux) Handle(pattern string, handler Handler) Handle注册给定模式的处理程序。如果已经存在用于模式的处理程序,则Handle发出运行时恐慌(panic)。 Example mux := http.NewServeMux() mux.Handle("/api/", apiHandler{}) mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { // “/”模式匹配所有内容,因此我们需要检查我们是否在root这里。 if req.URL.Path != "/" { http.NotFound(w, req) return } fmt.Fprintf(w, "Welcome to the home page!") }) func (*ServeMux) HandleFunc func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) HandleFunc注册给定模式的处理函数。 func (*ServeMux) Handler func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) Handler通过访问r.Method,r.Host和r.URL.Path返回用于给定请求的处理程序。 它总是返回一个非nil handler。 如果路径的格式不规范,则该handler将是内部生成的handler,该handler将重定向到规范路径。 如果主机包含端口,则在匹配处理程序时将忽略该端口。 path和host不做变更直接用于CONNECT请求。 Handler还会返回与请求匹配的已注册模式,如果是内部生成的重定向,则返回在跟随重定向之后将匹配的模式。 如果没有适用于该请求的注册handler,则处理程序返回一个“找不到页面'”处理程序和一个空模式。 func (*ServeMux) ServeHTTP func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) ServeHTTP将请求调度到其模式与请求URL最匹配的处理程序。 type Server type Server struct { Addr string // 监听的TCP地址 , 如果为空,则为":http" Handler Handler // 要调用的处理程序,如果为空则为 http.DefaultServeMux // TLSConfig可选地提供TLS配置,以供ServeTLS和ListenAndServeTLS使用。 // 请注意,此值由ServeTLS和ListenAndServeTLS克隆, // 因此无法使用tls.Config.SetSessionTicketKeys之类的方法修改配置。 // 若要使用SetSessionTicketKeys,请改为将Server.Serve与TLS侦听器一起使用。 TLSConfig *tls.Config // ReadTimeout是读取整个请求(包括请求体)的最大持续时间。 // 由于ReadTimeout不允许处理程序根据每个请求体的可接受截止日期或上载速率做出每个请求的决定, // 因此大多数用户将更喜欢使用ReadHeaderTimeout。 两者都使用也是有效的。 ReadTimeout time.Duration // ReadHeaderTimeout是允许读取请求头的时间量。 // 读取请求体后,将重置连接的读取截止时间,并且Handler可以确定对Body而言太慢的速度。 // 如果ReadHeaderTimeout为零,则使用ReadTimeout的值。 如果两者均为零,则没有超时。 ReadHeaderTimeout time.Duration // WriteTimeout是写入响应超时之前的最大持续时间。 // 每当读取新请求头时,都会将其重置。 // 与ReadTimeout一样,它也不允许处理程序根据每个请求做出决策。 WriteTimeout time.Duration // IdleTimeout是启用保持活动状态后等待下一个请求的最长时间。 // 如果IdleTimeout为零,则使用ReadTimeout的值。 如果两者均为零,则没有超时。 IdleTimeout time.Duration // MaxHeaderBytes控制服务器读取的最大字节数,以解析请求头的键和值(包括请求行)。 // 它不限制请求体的大小。 如果为零,则使用DefaultMaxHeaderBytes。 MaxHeaderBytes int // TLSNextProto可以选择指定一个函数,以在进行NPN/ALPN协议升级时接管所提供的TLS连接的所有权。 // map的key是协商的协议名称。 Handler参数应用于处理HTTP请求, // 并将初始化请求的TLS和RemoteAddr(如果尚未设置)。 函数返回时,连接将自动关闭。 // 如果TLSNextProto不为nil,则不会自动启用HTTP/2支持。 TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // ConnState指定一个可选的回调函数,当客户端连接更改状态时调用该函数。 // 有关详细信息,请参见ConnState类型和关联的常量。 ConnState func(net.Conn, ConnState) // ErrorLog指定一个可选的记录器,用于接收连接的错误, // 来自处理程序的意外行为以及潜在的FileSystem错误。 // 如果为nil,则通过日志包的标准记录器完成记录。 ErrorLog *log.Logger // BaseContext可以选择指定一个函数,该函数返回此服务器上传入请求的基本context。 // 提供的侦听器是即将开始接收请求的特定侦听器。 // 如果BaseContext为nil,则默认值为context.Background()。 如果为非nil,则它必须返回非nil Context。 BaseContext func(net.Listener) context.Context // ConnContext可选地指定一个函数,该函数修改用于新连接的上下文c。 // 提供的ctx派生自基本上下文,并且具有ServerContextKey值。 ConnContext func(ctx context.Context, c net.Conn) context.Context disableKeepAlives int32 // accessed atomically. inShutdown int32 // accessed atomically (non-zero means we're in Shutdown) nextProtoOnce sync.Once // guards setupHTTP2_* init nextProtoErr error // result of http2.ConfigureServer if used mu sync.Mutex listeners map[*net.Listener]struct{} activeConn map[*conn]struct{} doneChan chan struct{} onShutdown []func() } Server定义用于运行HTTP服务器的参数。服务器的零值是有效配置。 func (*Server) Close func (srv *Server) Close() error Close立即关闭所有活动的net.Listeners以及状态StateNew,StateActive或StateIdle中的所有连接。 要优雅的关机,请使用Shutdown。 Close不会尝试关闭(甚至不知道)任何被劫持的连接,例如WebSockets。 Close返回从关闭服务器的基础侦听器返回的任何错误。 func (*Server) ListenAndServe func (srv *Server) ListenAndServe() error ListenAndServe侦听TCP网络地址srv.Addr,然后调用Serve处理传入连接上的请求。 接受的连接配置为启用TCP保持活动状态。 如果srv.Addr为空,则使用“:http”。 ListenAndServe始终返回非nil错误。 Shutdown或Close后,返回的错误为ErrServerClosed。 func (*Server) ListenAndServeTLS func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error ListenAndServeTLS侦听TCP网络地址srv.Addr,然后调用ServeTLS处理传入TLS连接上的请求。 接受的连接配置为启用TCP keep-alives。 如果未填充服务器的TLSConfig.Certificates或TLSConfig.GetCertificate,则必须提供包含证书和服务器匹配私钥的文件名。 如果证书是由证书颁发机构签名的,则certFile应该是服务器证书,任何中间件和CA证书的串联。 如果srv.Addr为空,则使用“:https”。 ListenAndServeTLS始终返回非nil错误。 Shutdown或Close后,返回的错误为ErrServerClosed。 func (*Server) RegisterOnShutdown func (srv *Server) RegisterOnShutdown(f func()) RegisterOnShutdown注册一个函数来调用Shutdown。 这可用于正常关闭已进行NPN/ALPN协议升级或被劫持的连接。 此功能应启动特定于协议的正常关机,但不应等待关机完成。 func (*Server) Serve func (srv *Server) Serve(l net.Listener) error 服务在侦听器l上接受传入连接,为每个连接创建一个新的服务goroutine。 服务goroutine读取请求,然后调用srv.Handler对其进行回复。 仅当侦听器返回*tls.Conn连接并且在TLSConfig.NextProtos中将它们配置为“h2”时,才启用HTTP/2支持。 服务始终返回非零错误并关闭l。 Shutdown或Close后,返回的错误为ErrServerClosed。 func (*Server) ServeTLS func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error ServeTLS在侦听器l上接受传入连接,为每个连接创建一个新的服务goroutine。 服务goroutine会执行TLS设置,然后读取请求,并调用srv.Handler对其进行回复。 如果未填充服务器的TLSConfig.Certificates或TLSConfig.GetCertificate,则必须提供包含证书和服务器匹配私钥的文件。 如果证书是由证书颁发机构签名的,则certFile应该是服务器证书,任何中间件和CA证书的串联。 ServeTLS始终返回非nil错误。 Shutdown或Close后,返回的错误为ErrServerClosed。 func (*Server) SetKeepAlivesEnabled func (srv *Server) SetKeepAlivesEnabled(v bool) SetKeepAlivesEnabled控制是否启用HTTP keep-alive。默认情况下,始终启用keep-alives状态。只有在资源非常有限的环境或正在关闭的服务器中才能禁用它们。 func (*Server) Shutdown func (srv *Server) Shutdown(ctx context.Context) error Shutdown可以优雅的关闭服务器,而不会中断任何活动的连接。Shutdown的工作方式是先关闭所有打开的侦听器,然后关闭所有空闲连接,然后无限期等待连接返回到空闲状态,然后关闭。如果提供的上下文在关闭完成之前到期,则Shutdown返回上下文的错误,否则它将返回从关闭服务器的基础侦听器返回的任何错误。 调用Shutdown时,Serve,ListenAndServe和ListenAndServeTLS立即返回ErrServerClosed。确保程序没有退出,而是等待Shutdown返回。 Shutdown不会尝试关闭也不等待被劫持的连接,例如WebSockets。如果需要,Shutdown的调用者应单独通知此类长期存在的连接,并等待它们关闭。有关注册关闭通知功能的方法,请参见RegisterOnShutdown。 一旦在服务器上调用了Shutdown,就可能无法重用它。将来对诸如Serve之类的方法的调用将返回ErrServerClosed。 Example var srv http.Server idleConnsClosed := make(chan struct{}) go func() { sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt) <-sigint // We received an interrupt signal, shut down. if err := srv.Shutdown(context.Background()); err != nil { // Error from closing listeners, or context timeout: log.Printf("HTTP server Shutdown: %v", err) } close(idleConnsClosed) }() if err := srv.ListenAndServe(); err != http.ErrServerClosed { // Error starting or closing listener: log.Fatalf("HTTP server ListenAndServe: %v", err) } <-idleConnsClosed type Transport type Transport struct { // Proxy指定一个函数来返回给定请求的代理。 // 如果函数返回非零错误,则请求将中止并提供所提供的错误。 // Proxy类型由URL scheme确定。 支持“http”,“ https”和“socks5”。 // 如果scheme为空,则假定为“http”。 如果Proxy为nil或返回nil *URL,则不使用任何代理。 Proxy func(*Request) (*url.URL, error) // DialContext指定用于创建未加密的TCP连接的拨号功能。 // 如果DialContext为nil(并且下面弃用的Dial也为nil),则Transport使用程序包net进行调用。 // DialContext与RoundTrip的调用同时运行。 当较早的连接在以后的DialContext完成之前变为空闲时, // 发起调用的RoundTrip调用可能会使用先前调用的连接结束。 DialContext func(ctx context.Context, network, addr string) (net.Conn, error) // Dial指定用于创建未加密的TCP连接的拨号功能。 Dial与RoundTrip的调用同时运行。 // 当较早的连接在之后的Dial完成之前变为空闲时,发起Dial的RoundTrip调用可能会使用先前调动的连接结束。 // 弃用:改用DialContext,它允许Transport在不再需要调用时立即取消Dial。 // 如果两者都设置,则DialContext优先。 Dial func(network, addr string) (net.Conn, error) // DialTLS指定用于为非代理HTTPS请求创建TLS连接的可选Dial功能。 // 如果DialTLS为nil,则使用Dial和TLSClientConfig。 // 如果设置了DialTLS,则Dial挂钩不用于HTTPS请求,并且TLSClientConfig和TLSHandshakeTimeout将被忽略。 // 假定返回的net.Conn已通过TLS握手。 DialTLS func(network, addr string) (net.Conn, error) // TLSClientConfig指定要与tls.Client一起使用的TLS配置。 // 如果为nil,则使用默认配置。 如果为非nil,则默认情况下可能不会启用HTTP/2支持。 TLSClientConfig *tls.Config // TLSHandshakeTimeout指定等待TLS握手的最长时间。 零表示没有超时。 TLSHandshakeTimeout time.Duration // DisableKeepAlives(如果为true)将禁用HTTP keep-alives,并且仅将与服务器的连接用于单个HTTP请求。 // 这与类似命名的TCP keep-alives。 DisableKeepAlives bool // DisableCompression如果为true,则当请求不包含现有的Accept-Encoding值时, // 阻止Transport使用“Accept-Encoding:gzip”请求Header请求压缩。 // 如果Transport请求gzip并获得gzip压缩的响应,则会在Response.Body中对其进行透明解码。 // 但是,如果用户明确请求gzip,则不会自动将其解压缩。 DisableCompression bool // MaxIdleConns控制所有主机之间的最大空闲(keep-alive)连接数。 零表示无限制。 MaxIdleConns int // MaxIdleConnsPerHost(如果非零)控制最大空闲(keep-alive)连接以保留每个主机。 // 如果为零,则使用DefaultMaxIdleConnsPerHost。 MaxIdleConnsPerHost int // MaxConnsPerHost可以选择限制每个主机的连接总数, // 包括处于拨号,活动和空闲状态的连接。 超出限制时,拨号将阻塞。 零表示无限制。 MaxConnsPerHost int // IdleConnTimeout是空闲(keep-alive)连接在关闭自身之前将保持空闲状态的最长时间。 // 零表示无限制。 IdleConnTimeout time.Duration // ResponseHeaderTimeout(如果非零)指定在完全写入请求(包括其Body(如果有)) // 之后等待服务器的响应头的时间。 该时间不包括读取响应体的时间。 ResponseHeaderTimeout time.Duration // ExpectContinueTimeout(如果非零)指定如果请求具有“Expect: 100-continue”header, // 则在完全写入请求头之后等待服务器的第一个响应头的时间。 // 零表示没有超时,并导致请求体立即发送,而无需等待服务器批准。 此时间不包括发送请求头的时间。 ExpectContinueTimeout time.Duration // TLSNextProto指定在TLS NPN/ALPN协议协商之后,Transport如何切换到备用协议(例如HTTP/2)。 // 如果Transport使用非空协议名称调用TLS连接,并且TLSNextProto包含该键的映射条目(例如“ h2”), // 则将以请求的权限(例如“example.com”或“example .com:1234“)和TLS连接。 // 该函数必须返回RoundTripper,然后再处理请求。 如果TLSNextProto不为nil,则不会自动启用HTTP/2支持。 TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper // ProxyConnectHeader可以选择指定在CONNECT请求期间发送给代理的header。 ProxyConnectHeader Header // MaxResponseHeaderBytes指定对服务器的响应头中允许的响应字节数的限制。 零表示使用默认限制。 MaxResponseHeaderBytes int64 // WriteBufferSize指定在写入Transport时使用的写入缓冲区的大小。 如果为零,则使用默认值(当前为4KB)。 WriteBufferSize int // ReadBufferSize指定从Transport读取时使用的读取缓冲区的大小。 如果为零,则使用默认值(当前为4KB)。 ReadBufferSize int // 当提供非零Dial,DialTLS或DialContext函数或TLSClientConfig时,ForceAttemptHTTP2控制是否启用HTTP/2。 // 默认情况下,保守地使用这些字段会禁用HTTP/2。要使用自定义Dial程序或TLS配置并仍尝试HTTP/2升级, // 请将其设置为true。 ForceAttemptHTTP2 bool idleMu sync.Mutex closeIdle bool // user has requested to close all idle conns idleConn map[connectMethodKey][]*persistConn // most recently used at end idleConnWait map[connectMethodKey]wantConnQueue // waiting getConns idleLRU connLRU reqMu sync.Mutex reqCanceler map[*Request]func(error) altMu sync.Mutex // guards changing altProto only altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme connsPerHostMu sync.Mutex connsPerHost map[connectMethodKey]int connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns } Transport是RoundTripper的实现,它支持HTTP,HTTPS和HTTP代理(对于HTTP或带CONNECT的HTTPS)。 默认情况下,Transport缓存连接以供将来重用。访问许多主机时,这可能会留下许多打开的连接。可以使用Transport的CloseIdleConnections方法以及MaxIdleConnsPerHost和DisableKeepAlives字段来管理此行为。 Transport应该被重用,而不是根据需要创建。多个goroutine并发使用Transport是安全的。Transport是用于发出HTTP和HTTPS请求的低级原语。有关Cookie和重定向之类的高级功能,请参阅Client。 Transport使用HTTP/1.1作为HTTP URL,HTTP/1.1或HTTP/2作为HTTPS URL,这取决于服务器是否支持HTTP/2,以及Transport的配置方式。 DefaultTransport支持HTTP/2。要在Transport上显式启用HTTP/2,请使用golang.org/x/net/http2并调用ConfigureTransport。有关HTTP/2的更多信息,请参见软件包文档。 状态代码在1xx范围内的响应将自动处理(100 expect-continue)或被忽略。一个例外是HTTP状态代码101(交换协议),它被认为是终止状态,由RoundTrip返回。若要查看被忽略的1xx响应,请使用httptrace跟踪包的ClientTrace.Got1xxResponse。 如果请求是幂等且没有请求体或已定义其Request.GetBody,则Transport仅在遇到网络错误时重试该请求。如果HTTP请求具有HTTP方法GET,HEAD,OPTIONS或TRACE,则它们被认为是幂等的。或者其header映射包含“Idempotency-Key”或“ X-Idempotency-Key”条目。如果幂等键值为零长度切片,则将请求视为幂等,但header不会在被发送出去。 func (*Transport) Clone func (t *Transport) Clone() *Transport Clone返回t导出字段的深层副本。 func (*Transport) CloseIdleConnections func (t *Transport) CloseIdleConnections() CloseIdleConnections关闭先前与以前的请求建立连接但现在处于“keep-alive”状态的空闲连接。它不会中断当前正在使用的任何连接。 func (*Transport) RegisterProtocol func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) RegisterProtocol使用scheme注册新协议。 Transport将使用给定scheme将请求传递给rt。 模拟HTTP请求语义是rt的责任。 其他包可以使用RegisterProtocol提供协议scheme的实现,例如“ftp”或“file”。 如果rt.RoundTrip返回ErrSkipAltProtocol,则Tramsport将为该请求处理RoundTrip本身,就像未注册协议一样。 func (*Transport) RoundTrip func (t *Transport) RoundTrip(req *Request) (*Response, error) RoundTrip实现RoundTripper接口。 有关更高级别的HTTP客户端支持(例如cookie和重定向的处理),请参阅Get,Post和Client类型。 与RoundTripper界面类似,RoundTrip返回的错误类型未指定。

package httputil 阅读更多

import "net/http/httputil" httputil包提供HTTP实用函数,补充net/http包中更常见的函数。 Variables var ErrLineTooLong = internal.ErrLineTooLong 当读取格式不正确的带有过长行的块数据时,将返回ErrLineTooLong。 func DumpRequest func DumpRequest(req *http.Request, body bool) ([]byte, error) DumpRequest以HTTP/1.x连接形式返回给定的请求。 它只应该被服务端用来调试客户端请求。 返回值只是一个近似值; 在将初始请求解析为 http.Request 时,会丢失初始请求的一些细节。 特别是,头字段名称的顺序和大小写都会丢失。 多值标头中值的顺序保持不变。 HTTP/2请求以 HTTP/1.x 的形式被转储,而不是原始的二进制表示形式。 如果 body 为 true,则 DumpRequest 也会返回 body。 为此,它获取 req.Body 然后用一个新的 io.ReaderCloser 替换它来生成相同字节的。 如果 DumpRequest 返回一个错误,那么说明 req 的状态是未定义的。 http.Request.Write文档详细说明了转储中包括哪些req字段。 DumpRequest Example ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { dump, err := httputil.DumpRequest(r, true) if err != nil { http.Error(w, fmt.Sprint(err), http.StatusInternalServerError) return } fmt.Fprintf(w, "%q", dump) })) defer ts.Close() const body = "Go is a general-purpose language designed with systems programming in mind." req, err := http.NewRequest("POST", ts.URL, strings.NewReader(body)) if err != nil { log.Fatal(err) } req.Host = "www.example.org" resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s", b) // output "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nContent-Length: 75\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind." func DumpRequestOut func DumpRequestOut(resp *http.Response, body bool)([]byte, error) DumpRequestOut类似于DumpRequest,但用于传出客户端请求。它包括标准http.Transport添加的任何标头,例如User-Agent。 DumpRequestOut Example const body = "Go is a general-purpose language designed with systems programming in mind." req, err := http.NewRequest("PUT", "http://www.example.org", strings.NewReader(body)) if err != nil { log.Fatal(err) } dump, err := httputil.DumpRequestOut(req, true) if err != nil { log.Fatal(err) } fmt.Printf("%q", dump) // Output "PUT / HTTP/1.1\r\nHost: www.example.org\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 75\r\nAccept-Encoding: gzip\r\n\r\nGo is a general-purpose language designed with systems programming in mind." func DumpResponse func DumpResponse(resp *http.Response, body bool) ([]byte, error) DumpResponse类似于DumpRequest,但转储响应。 DumpResponse Example const body = "Go is a general-purpose language designed with systems programming in mind." ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Date", "Wed, 19 Jul 1972 19:00:00 GMT") fmt.Fprintln(w, body) })) defer ts.Close() resp, err := http.Get(ts.URL) if err != nil { log.Fatal(err) } defer resp.Body.Close() dump, err := httputil.DumpResponse(resp, true) if err != nil { log.Fatal(err) } fmt.Printf("%q", dump) // Output "HTTP/1.1 200 OK\r\nContent-Length: 76\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Wed, 19 Jul 1972 19:00:00 GMT\r\n\r\nGo is a general-purpose language designed with systems programming in mind.\n" func NewChunkedReader func NewChunkedReader(r io.Reader) io.Reader NewChunkedReader返回一个新的chunkedReader,该块将从r读取的数据转换为HTTP“分块”格式,然后再返回。读取最后的0-length的块时,chunkedReader返回io.EOF。 普通应用程序不需要NewChunkedReader。读取响应正文时,http包会​​自动解码分块。 func NewChunkedWriter func NewChunkedWriter(w io.Writer) io.WriteCloser NewChunkedWriter 返回一个新的 chunkedWriter,它将写入转换为 HTTP“分块”格式,然后写入到 w。关闭返回的chunkedWriter将发送标记为流结束的最后一个0-length的块,但不发送出现在trailer的最后一个CRLF;trailer和最后的CRLF必须分开写。 普通的应用程序不需要 NewChunkedWriter。 如果处理程序没有设置 Content-Length 标头,http 包会自动添加 chunking。 在处理程序中使用 NewChunkedWriter 将导致双重块或者Content-Length长度的分块,这两种情况都是错误的。 type BufferPool type BufferPool interface{ Get() []byte Put([]byte) } BufferPool是用于获取和返回由io.CopyBuffer使用的临时字节切片的接口。 type ReverseProxy type ReverseProxy struct { // Director必须具有将请求修改为要使用Transport发送的新请求的函数。 // 然后将其响应复制回未经修改的原始客户端。Director 返回后不得访问提供的请求。 Diretor func(*http.Request) // Transport用于代理请求,如果是nil,那么使用 http.DefaultTransport Transport http.RoundTripper // FlushInterval指定在复制响应主体时要刷新到客户端的刷新间隔。 // 如果为零,则不执行定期刷新。负值表示每次写入客户端后立即刷新。 // 当ReverseProxy将响应识别为流响应时,将忽略FlushInterval。 // 对于此类响应,立即将写操作刷新到客户端 FlushInterval time.Duration // ErrorLog为尝试代理请求时发生的错误指定一个可选的记录器。 // 如果为nil,则通过日志包的标准记录器完成记录。 ErrorLog *log.Logger // BufferPool可以选择指定一个缓冲池, // 以在复制HTTP响应正文时获取io.CopyBuffer使用的字节切片。 BufferPool BufferPool // ModifyResponse是一个可选函数,用于修改后端的响应。 // 如果后端完全返回带有任何HTTP状态代码的响应,则调用该方法。 // 如果后端不可达,则调用可选的ErrorHandler而不调用ModifyResponse。 // 如果ModifyResponse返回错误,则会使用错误值调用ErrorHandler。 // 如果ErrorHandler为nil,则使用其默认实现。 ModifyResponse func(*http.Response) error // ErrorHandler是一个可选函数,用于处理到达后端的错误或ModifyResponse中的错误。 // 如果为nil,则默认是记录所提供的错误并返回 502 Bad Gateway 响应。 ErrorHandler func(http.ResponseWriter, *http.Request, error) } ReverseProxy是一个HTTP处理程序,它接收传入的请求并将其发送到另一台服务器,并将响应代理回客户端。 ReverseProxy Example backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "this call was relayed by the reverse proxy") })) defer backendServer.Close() rpURL, err := url.Parse(backendServer.URL) if err != nil { log.Fatal(err) } frontendProxy := httptest.NewServer(httputil.NewSingleHostReverseProxy(rpURL)) defer frontendProxy.Close() resp, err := http.Get(frontendProxy.URL) if err != nil { log.Fatal(err) } b, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s", b) // Output this call was relayed by the reverse proxy func NewSingleHostReverseProxy func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy NewSingleHostReverseProxy返回一个新的ReverseProxy,将URL路由到target中提供的scheme,host和base path。 如果目标的路径是"/base",而传入的请求是"/dir",则目标请求将是"/base/dir"。 NewSingleHostReverseProxy不会重写Host标头。 要重写Host标头,请直接将ReverseProxy与自定义Director一起使用。 func(*ReverseProxy) ServeHTTP func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)

package ioutil 阅读更多

import "io/ioutil" ioutil包实现了I/O实用工具。 变量 var Discard io.Writer = devNull(0) Discard是一个io.Writer,在该Writer上所有Write调用都可以在不执行任何操作的情况下成功完成。 函数NopCloser func NopCloser(r io.Reader) io.ReadCloser NopCloser返回一个ReadCloser,其中包含一个无操作(no-op)的Close方法,用于包装提供的Reader r。 函数ReadAll func ReadAll(r io.Reader) ([]byte, error) ReadAll从r读取,直到出现错误或EOF并返回它读取到的数据。成功的调用将返回err==nil,而不是err==EOF。因为ReadAll被定义为从src读取直到EOF,所以它不会将来自Read的EOF视为要报告的错误。 r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.") b, err := ioutil.ReadAll(r) if err != nil { log.Fatal(err) } fmt.Printf("%s", b) // 输出 Go is a general-purpose language designed with systems programming in mind. 函数ReadDir func ReadDir(dirname string) ([]os.FileInfo, error) ReadDir读取由dirname命名的目录,并返回按filename排序的目录条目列表。 files, err := ioutil.ReadDir(".") if err != nil { log.Fatal(err) } for _, file := range files { fmt.Println(file.Name()) } 函数ReadFile func ReadFile(filename string) ([]byte, error) ReadFile读取由filename命名的文件并返回内容。成功的调用将返回err==nil,而不是err==EOF。因为ReadFile读取整个文件,所以它不会将Read中的EOF视为要报告的错误。 content, err := ioutil.ReadFile("testdata/hello") if err != nil { log.Fatal(err) } fmt.Printf("File contents: %s", content) // 输出 File contents: Hello, Gophers! 函数TempDir func TempDir(dir, prefix string) (name string, err error) TempDir在目录dir中创建一个新的临时目录,其名称以prefix开头,并返回新目录的路径。如果dir是空字符串,TempDir将使用临时文件的默认目录(请参阅os.TempDir)。同时调用TempDir的多个程序将不会选择相同的目录。调用者有责任在不再需要时删除目录。 content := []byte("temporary file's content") dir, err := ioutil.TempDir("", "example") if err != nil { log.Fatal(err) } defer os.RemoveAll(dir) // clean up tmpfn := filepath.Join(dir, "tmpfile") if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil { log.Fatal(err) } 函数TempFile func TempFile(dir, pattern string) (f *os.File, err error) TempFile在目录dir中创建一个新的临时文件,打开文件进行读写,并返回生成的*os.File。文件名是通过获取pattern并在末尾添加随机字符串生成的。如果pattern包含“*”,则随机字符串将替换最后一个“*”。如果dir是空字符串,则TempFile使用临时文件的默认目录(请参阅os.TempDir)。同时调用TempFile的多个程序不会选择相同的文件。调用者可以使用f.Name()来查找文件的路径名。当不再需要时,调用者有责任删除该文件。 content := []byte("temporary file's content") tmpfile, err := ioutil.TempFile("", "example") if err != nil { log.Fatal(err) } defer os.Remove(tmpfile.Name()) // clean up if _, err := tmpfile.Write(content); err != nil { log.Fatal(err) } if err := tmpfile.Close(); err != nil { log.Fatal(err) }content := []byte("temporary file's content") tmpfile, err := ioutil.TempFile("", "example.*.txt") if err != nil { log.Fatal(err) } defer os.Remove(tmpfile.Name()) // clean up if _, err := tmpfile.Write(content); err != nil { tmpfile.Close() log.Fatal(err) } if err := tmpfile.Close(); err != nil { log.Fatal(err) } 函数WriteFile func WriteFile(filename string, data []byte, perm os.FileMode) error WriteFile将数据写入由filename命名的文件。如果该文件不存在,则WriteFile使用权限perm创建它;否则WriteFile会在写入之前截断它。 message := []byte("Hello, Gophers!") err := ioutil.WriteFile("testdata/hello", message, 0644) if err != nil { log.Fatal(err) }

package js 阅读更多

import "syscall/js" 使用js/wasm体系结构时,使用js包可以访问WebAssembly主机环境。其API基于JavaScript语义。 这个软件包是实验性的。当前的范围仅是允许运行测试,而尚未为用户提供全面的API。它不受Go兼容性承诺的约束。 func CopyBytesToGo func CopyBytesToGo(dst []byte, src Value) int CopyBytesToGo将字节从Uint8Array src复制到dst。它返回复制的字节数,这将是src和dst的最小长度。如果src不是Uint8Array,则CopyBytesToGo会出现panic。 func CopyBytesToJS func CopyBytesToJS(dst Value, src []byte) int CopyBytesToJS将字节从src复制到Uint8Array dst。它返回复制的字节数,这将是src和dst的最小长度。如果dst不是Uint8Array,则CopyBytesToJS会出现panic。 type Error type Error struct { // Value 是基础的JavaScript错误值。 Value } Error包装了JavaScript错误。 func (Error) Error func (e Error) Error() string Error实现了error接口。 type Func type Func struct { Value // 调用Go函数的JavaScript函数 id uint32 } Func是包装的Go函数,将由JavaScript调用。 func FuncOf func FuncOf(fn func(this Value, args []Value) interface{}) Func FuncOf返回包装的函数。 调用JavaScript函数将使用JavaScript的“this”关键字的值和调用的参数来同步调用Go函数fn。 调用的返回值是根据ValueOf将Go函数映射回JavaScript的结果。 在从Go到JavaScript的调用期间触发的包装函数将在同一goroutine上执行。 由JavaScript的事件循环触发的包装函数将在额外的goroutine上执行。 包装函数中的阻塞操作将阻塞事件循环。 如果一个包装函数被阻止,其他包装函数将不被处理。 因此,阻塞函数应显式启动新的goroutine。 当不再使用该函数时,必须调用Func.Release以释放资源。 example var cb js.Func cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} { fmt.Println("button clicked") cb.Release() // release the function if the button will not be clicked again return nil }) js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb) func (Func) Release func (c Func) Release() Release释放为该函数分配的资源。调用Release之后不得调用该函数。 type Type type Type int Type代表Value的JavaScript类型。 const ( TypeUndefined Type = iota TypeNull TypeBoolean TypeNumber TypeString TypeSymbol TypeObject TypeFunction ) func (Type) String func (t Type) String() string type Value type Value struct { ref ref } Value表示JavaScript值。零值为JavaScript值“undefined”。 func Global func Global() Value Global返回JavaScript全局对象,通常是“window”或“global”。 func Null func Null() Value Null返回JavaScript值“ null”。 func Undefined func Undefined() Value Undefined返回JavaScript值“undefined”。 func ValueOf func ValueOf(x interface{}) Value ValueOf返回x作为JavaScript值: Go JavaScript js.Value [its value] js.Func function nil null bool boolean integers and floats number string string []interface new array map[string]interface new object 如果x不是期望的类型之一,则发生panic。 func (Value) Bool func (v Value) Bool() bool Bool返回值v作为布尔。如果v不是JavaScript布尔值则返回panic。 func (Value) Call func (v Value) Call(m string, args ...interface{}) Value Call使用给定的参数对值v的方法m进行JavaScript调用。如果v没有方法m则返回panic。根据ValueOf函数将参数映射到JavaScript值。 func (Value) Float func (v Value) Float() float64 Float返回值v作为float64。如果v不是JavaScript的数字,则返回panic。 func (Value) Get func (v Value) Get(p string) Value Get返回值v的JavaScript属性p。如果v不是JavaScript对象,则返回panic。 func (Value) Index func (v Value) Index(i int) Value Index返回值为v的JavaScript索引i。如果v不是JavaScript对象,则返回panic。 func (Value) InstanceOf func (v Value) InstanceOf(t Value) bool InstanceOf根据JavaScript的instanceof运算符报告v是否是类型t的实例。 func (Value) Int func (v Value) Int() int Int返回截断为int的值v。如果v不是JavaScript的数字,则返回panic。 func (Value) Invoke func (v Value) Invoke(args ...interface{}) Value Invoke使用给定的参数对值v进行JavaScript调用。如果v不是JavaScript函数,则返回panic。根据ValueOf函数将参数映射到JavaScript值。 func (Value) JSValue func (v Value) JSValue() Value JSValue实现Wrapper接口。 func (Value) Length func (v Value) Length() int Length返回v的JavaScript属性“ length”。如果v不是JavaScript对象,则返回panic。 func (Value) New func (v Value) New(args ...interface{}) Value New使用JavaScript的“ new”运算符,将值v作为构造函数和给定参数。如果v不是JavaScript函数,则返回panic。根据ValueOf函数将参数映射到JavaScript值。 func (Value) Set func (v Value) Set(p string, x interface{}) Set将值v的JavaScript属性p设置为ValueOf(x)。如果v不是JavaScript对象,则返回panic。 func (Value) SetIndex func (v Value) SetIndex(i int, x interface{}) SetIndex将值v的JavaScript索引i设置为ValueOf(x)。如果v不是JavaScript对象,则返回panic。 func (Value) String func (v Value) String() string String返回值v作为字符串。 由于Go的String方法约定,所以String是一种特殊情况。 与其他getter不同,如果v的Type不是TypeString,不会返回panic。 而是返回格式为“<T>”或“<T:V>”的字符串,其中T是v的类型,V是v的值的字符串表示形式。 func (Value) Truthy func (v Value) Truthy() bool Truthy返回值v的JavaScript“真实性”。在JavaScript中,false,0,“”,null,undefined和NaN为“falsy”,其他所有内容均为“truthy”,更多内容点击这里。 func (Value) Type func (v Value) Type() Type Type返回值v的JavaScript类型。它类似于JavaScript的typeof运算符,不同之处在于它返回TypeNull而不是TypeObject表示null。 type ValueError type ValueError struct { Method string Type Type } 在不支持Value的Value方法上调用Value方法时,会发生ValueError。在每种方法的说明中都记录了这种情况。 func (*ValueError) Error func (e *ValueError) Error() string type Wrapper type Wrapper interface { // JSValue returns a JavaScript value associated with an object. JSValue() Value } Wrapper由JavaScript值支持的类型实现。

package rpc 阅读更多

import "net/rpc" rpc包提供对通过网络或其他I/O连接的对象导出方法的访问。服务端注册一个对象,使它作为具有对象类型名称的服务而可见。在注册之后,对象的导出方法可以被远程访问。服务端可以注册不同类型的多个对象,但是如果注册同一类型的多个对象是错误的。 只有满足这些标准的方法才可用于远程访问,其他方法将被忽略: 方法的类型是导出的 方法是导出的 方法有两个参数,都是导出或内置类型 方法的第二个参数是一个指针 方法有返回error类型 实际上,该方法看起来应该像这样: func (t *T) MethodName(argType T1, replyType *T2) error 其中T1和T2可以通过encoding/gob编码、即使使用不同的编解码器,这些要求也是适用的。(在将来,这些要求可能会对自定义编解码器弱化)。 方法的第一个参数:表示调用方提供的参数 方法的第二个参数:表示要返回给调用方的结果参数 该方法的返回值(如果不是nil)将作为字符串传递回来,客户端将认为它是由errors.New创建的。如果有错误被返回,则不会有响应参数发送给客户端。 服务端可以通过调用ServerConn来处理单个连接上的请求。更常见的情况是,服务端创建一个网络监听器,然后调用Accept,或者创建一个HTTP监听器,然后调用HandleHTTP和http.Serve。 想要使用该服务的客户端会建立一个连接,然后在连接上调用NewClient。Dial(DialHTTP)函数为原始网络连接(HTTP连接)执行这两个步骤,然后得到的客户端对象有两个方法Call和Go,它们指定要调用的服务和方法,一个传递参数的指针和一个接收结果参数的指针。 Call方法:等待远程调用完成 Go方法:异步启动调用,并使用Call结构体中的Done通道发出完成信号 除非设置了显式编解码器,否则将使用encoding/gob包来传输数据。 下面是一个示例,服务端希望导出Arith类型的对象: package server import "errors" type Args struct { A, B int } type Quotient struct { Quo, Rem int } type Arith int func (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil } func (t *Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("divide by zero") } quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil } 服务端调用HTTP服务: arith := new(Arith) rpc.Register(arith) rpc.HandleHTTP() l, e := net.Listen("tcp", ":1234") if e != nil { log.Fatal("listen error:", e) } go http.Serve(l, nil) 此时,客户端可以服务“Arith”带有方法“Arith.Multiply”和“Arith.Divide”。要调用这些方法,客户端首先要连接服务端: client, err := rpc.DialHTTP("tcp", serverAddress + ":1234") if err != nil { log.Fatal("dialing:", err) } 然后,客户端可以执行一次远程调用: // Synchronous call args := &server.Args{7,8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply) 或者: // Asynchronous call quotient := new(Quotient) divCall := client.Go("Arith.Divide", args, quotient, nil) replyCall := <-divCall.Done // will be equal to divCall // check errors, print, etc. 服务端实现通常会为客户端提供简单的类型安全包装器,net/rpc包已经暂停,不会在接受新特性。 Constants const ( // Defaults used by HandleHTTP DefaultRPCPath = "/_goRPC_" DefaultDebugPath = "/debug/rpc" ) Variables var DefaultServer = NewServer() // DefaultServer是 *Server的默认实例 var ErrShutdown = errors.New("connection is shut down") func Accpet func Accept(lis net.Listener) Accept接受监听器上的连接,并为每个传入连接向DefaultServer提供请求。Accept可能会被阻塞,通常调用则在go语句中调用它。 func HandleHTTP func HandleHTTP() HandleHTTP在DefaultRPCPath上为RPC消息注册一个HTTP处理器到DefaultServer上,并在DefaultDebugPath上注册一个调试器。仍然需要调用http.Serve(),通常也是在go语句中。 func Register func Register(rcvr interface{}) error Register 在 DefaultServer 中发布接收方的方法。 func RegisterName func RegisterName(name string, rcvr interface{}) error Registername 类似于 Register,但使用提供的类型名称而不是接收方的具体类型。 func ServeCodec func ServeCodec(codec ServerCodec) Servecodec 类似于 ServeConn,但使用指定的编解码器对请求进行解码并对响应进行编码。 func ServeConn func ServeConn(conn io.ReadWriteCloser) ServeConn在单个连接上运行DefaultServer,ServeConn可能会被阻塞,在客户端挂起之前为连接提供服务。通常情况下,调用者在go语句中调用ServeConn。ServeConn在连接上使用gob编码格式。若要使用另外的编解码器,使用ServeCodec。有关并发访问的信息,查看NewClient的注释。 func ServeRequest func ServeRequest(codec ServeCodec) error Serverequest 类似于 ServeCodec,但同步服务于单个请求。 它不会在完成时关闭编解码器。 type call type Call struct { ServiceMethod string // 要调用的服务和方法的名称 Args interface{} // function (*struct)的传入参数 Reply interface{} // function (*struct)的返回结果 Error error // 完成后的错误状态 Done chan *Call // 调用结束后发出消息 } Call 表示一个活跃的RPC。 type Client type Client struct { codec ClientCodec reqMutex sync.Mutex // protects following request Request mutex sync.Mutex // protects following seq uint64 pending map[uint64]*Call closing bool // user has called Close shutdown bool // server has told us to stop } Client表示一个RPC客户端,一个Client可能有多个未完成的调用,一个Client也可能同时被多个goroutine使用。 func Dial func Dial(network, address string) (*Client, error) Dial按照到指定网络地址连接到RPC服务器。 func DialHTTP func DialHTTP(network, address string) (*Client, error) DialHTTP按照指定网络地址连接到HTTP RPC服务器,并监听默认的HTTP RPC 路径。 func DialHTTPPath func DialHTTPPath(network, address, path string) (*Client, error) DialHTTPPath 按照指定的网络地址和路径连接到 HTTP RPC 服务器。 func NewClient func NewClient(conn io.ReadWriteCloser) *Client Newclient 返回一个新 Client 来处理连接另一端的服务集发出的请求。 它向连接的写入端添加一个缓冲区,以便将头和有效负载作为一个单元发送。 连接的读取和写入部分是独立串行化的,因此不需要内联锁。 但是,每一部分都可以被并发的访问,因此 conn 的实现应该能够防止并发读或并发写。 func NewClientWithCodec func NewClientWithCodec(codec ClientCodec) *Client Newclientwithcodec 类似于 NewClient,但是使用指定的 codec 对请求进行编码并解码响应。 func (*Client) Call func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error Call调用指定名字的函数,等待它完成,并返回它的错误状态。 func (*Client) Close func (client *Client) Close() error Close 调用底层编解码器的 Close 方法。 如果连接已经关闭,则返回 ErrShutdown。 func (*Client) Go func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call Go 以异步方式调用函数。 它返回表示调用的 Call 结构体。 通过返回相同的 Call 对象,done 通道将在调用完成时发出信号。 如果 done 为 nil,则 Go 将分配一个新的通道,如果不是nil,done必然已经被填充否则Go将会奔溃。 type ClientCodec type ClientCodec interface { WriteRequest(*Request, interface{}) error ReadResponseHeader(*Response) error ReadResponseBody(interface{}) error Close() error } Clientcodec 实现在一个RPC会话的客户端侧写入RPC请求和读取RPC响应。客户端调用 WriteRequest 向连接写入请求,并成对调用 ReadResponseHeader 和 ReadResponseBody 来读取响应。 当连接结束时,客户端调用 Close。 可以使用 nil 参数调用 ReadResponseBody,以强制读取响应主体,然后将其丢弃。 有关并发访问的信息,请参阅 NewClient 的注释。 type Request type Request struct { ServiceMethod string // format: "Service.Method" Seq uint64 // 客户端选择的序列号 next *Request // 服务器中的空闲列表 } Request 是在每个 RPC 调用之前写入的请求头。 它在内部使用,但在这里作为调试的帮助而记录在案,例如在分析网络流量时。 type Response type Response struct { ServiceMethod string // echoes that of the Request Seq uint64 // echoes that of the request Error string // error, if any. next *Response // for free list in Server } Response 是在每个 RPC 返回之前写入的响应头。 它在内部使用,但在这里作为调试的帮助而记录在案,例如在分析网络流量时。 type Server type Server struct { serviceMap sync.Map // map[string]*service reqLock sync.Mutex // protects freeReq freeReq *Request respLock sync.Mutex // protects freeResp freeResp *Response } Server 代表RPC服务器。 func (*Server) Accept func (server *Server) Accept(lis net.Listener) Accept接受监听器上的连接,并未每个传入的连接提供请求。当监听器返回一个非nil错误时,Accetp会被阻塞。通常在Go语句中调用Accept。 func (*Server) HandleHTTP func (server *Server) HandleHTTP(rpcPath, debugPath string) Handlehttp 在 rpcPath 上为 RPC 消息注册 HTTP 处理器,在 debugPath 上注册调试器。 仍然需要调用http.Serve(),通常在 go 语句中。 func (*Server) Register func (server *Server) Register(rcvr interface{}) error Register 在服务器中发布满足以下条件的接收器值的方法集: 导出类型的导出方法 两个参数都是导出类型 第二个参数值指针类型 一个error类型的返回值 如果接收器不是导出类型或者没有合适的方法,则返回一个错误。 它还使用log包记录错误。 客户端使用“ Type.Method”形式的字符串访问每个方法。 其中 Type 是接收方的具体类型。 func (*Server) RegisterName func (server *Server) RegisterName(name string, rcvr interface{}) error Registername 类似于 Register,但使用给定的类型名称而不是接收方的具体类型。 func (*Server) ServeCodec func (server *Server) ServeCodec(codec ServerCodec) Servecodec 类似于 ServeConn,但使用给定的编解码器对请求进行解码并对响应进行编码。 func (*Server) ServeConn func (server *Server) ServeConn(conn io.ReadWriteCloser) Serveconn 在单个连接上运行服务器。 Serveconn 可能会被阻塞,在客户端挂断之前为连接提供服务。 调用方通常在 go 语句中调用 ServeConn。 Serveconn 在连接上使用gob编码格式。 若要使用另外的编解码器,请使用 ServeCodec。 有关并发访问的信息,请参阅 NewClient 的注释。 func (*Server) ServeHTTP func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) ServeHTTP实现了一个http.Handler来响应RPC请求。 func (*Server) ServeRequest func (server *Server) ServeRequest(codec ServerCodec) error Serverequest 类似于 ServeCodec,但同步服务于单个请求。 它不会在完成时关闭编解码器。 type ServerCodec type ServerCodec interface { ReadRequestHeader(*Request) error ReadRequestBody(interface{}) error WriteResponse(*Response, interface{}) error // Close 可以被多次调用,并且必须是幂等的 Close() error } Servercodec 为 RPC 会话的服务器端实现对 RPC 请求的读取和 RPC 响应的写入。 服务器成对调用 readrequesttheader 和 ReadRequestBody 来读取来自连接的请求,并调用 WriteResponse 来写回应。 服务器在连接结束时调用 Close。 可以使用 nil 参数调用 ReadRequestBody,以强制读取和丢弃请求的主体。 有关并发访问的信息,请参阅 NewClient 的注释。 type ServerError type ServerError string Servererror 表示从 RPC 连接的远程端返回的错误。 func (ServerError) Error func (e ServerError) Error() string

package syslog 阅读更多

import "log/syslog" syslog包提供了一个简单的系统日志服务接口,可以通过使用UNIX domain sockets,UDP或TCP将消息发送到syslog守护程序。 只需调用一次Dial,因为在写入失败时,syslog客户端将尝试重新连接到服务器并再次写入。 syslog包已归档,不再接受新功能。一些外部包提供更多功能。看到:https://godoc.org/?q=syslog 函数NewLogger func NewLogger(p Priority, logFlag int) (*log.Logger, error) NewLogger()创建一个log.Logger,其输出将写入具有指定优先级的系统日志服务,即syslog工具和severity(优先级别)的组合。 logFlag是传递给log.New()以创建Logger的标志集(flag set)。 类型Priority type Priority int 优先级是syslog工具和serverity(优先级别)的组合。例如,LOG_ALERT|LOG_FTP从FTP工具发送警报serverity(优先级别)消息。默认serverity(优先级别)为LOG_EMERG;默认工具是LOG_KERN。 const ( // From /usr/include/sys/syslog.h. // These are the same on Linux, BSD, and OS X. LOG_EMERG Priority = iota LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG )const ( // From /usr/include/sys/syslog.h. // These are the same up to LOG_FTP on Linux, BSD, and OS X. LOG_KERN Priority = iota << 3 LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_FTP LOG_LOCAL0 LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 ) 函数Dail func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) Dial通过连接到指定网络的raddr地址来建立与日志守护程序的连接。每次写入返回的writer都会发送一条日志消息,其中包含工具和serverity(优先级别)和标记。 如果tag为空,则使用os.Args[0]。 如果网络为空,Dial将连接到本地syslog服务器。 否则,请参阅net.Dial的文档以获取network和raddr的有效值。 sysLog, err := syslog.Dial("tcp", "localhost:1234", syslog.LOG_WARNING|syslog.LOG_DAEMON, "demotag") if err != nil { log.Fatal(err) } fmt.Fprintf(sysLog, "This is a daemon warning with demotag.") sysLog.Emerg("And this is a daemon emergency with demotag.") 函数New func New(priority Priority, tag string) (*Writer, error) New()建立与系统日志守护程序的新连接。每次写入返回的writer都会发送一条日志消息,其中包含给定的优先级(syslog工具和serverity的组合)和前缀标记。如果tag为空,则使用os.Args[0]。 类型Writer type Writer struct { // 包含已过滤或未导出的字段 } Writer是一个syslog服务的连接。 方法 (*Writer) Alert func (w *Writer) Alert(m string) error Alert()记录serverity(优先级别)为LOG_ALERT的消息,忽略传递给New的severity(优先级别)。 方法 (*Writer) Close func (w *Writer) Close() error Close关闭与syslog守护程序的连接。 方法 (*Writer) Crit func (w *Writer) Crit(m string) errors Crit记录serverity(优先级别)为LOG_CRIT的消息,忽略传递给New的serverity。 方法 (*Writer) Debug func (w *Writer) Debug(m string) error Debug会记录serverity(优先级别)为LOG_DEBUG的消息,忽略传递给New的serverity。 方法 (*Writer) Emerg func (w *Writer) Emerg(m string) error Emerg记录serverity(优先级别)为LOG_EMERG的消息,忽略传递给New的serverity。 方法 (*Writer) Err func (w *Writer) Err(m string) error Err记录serverity(优先级别)为LOG_ERR的消息,忽略传递给New的serverity。 方法 (*Writer) Info func (w *Writer) Info(m string) error Info会记录serverity(优先级别)为LOG_INFO的消息,忽略传递给New的serverity。 方法 (*Writer) Notice func (w *Writer) Notice(m string) error 注意记录serverity(优先级别)为LOG_NOTICE的消息,忽略传递给New的serverity。 方法 (*Writer) Warning func (w *Writer) Warning(m string) error Warning会记录serverity(优先级别)为LOG_WARNING的消息,忽略传递给New的serverity。 方法 (*Writer) Write func (w *Writer) Write(b []byte) (int, error) Write将日志消息发送到syslog守护程序。

packages log 阅读更多

import "log" log包实现了一个简单的日志包,它定义了一种类型Logger,其中包含格式化输出的方法。 它还有一个预定义的“标准”Logger,可以通过辅助函数Print[f|ln],Fatal[f|ln]和Panic[f|ln]访问,使用这些辅助函数比手动创建Logger更容易使用。Logger写入标准错误输出并打印每个日志记录的时间和日期。 每条日志记录都在单独的行中输出:如果正在打印的消息未以换行符结尾,则Logger将会在行尾添加一个换行符。 Fatal函数在写入日志消息后调用os.Exit(1)。 Panic函数在写入日志消息后调用运行时恐慌(panic)。 常量 const ( Ldate = 1 << iota // 当地时区的日期: 2009/01/23 Ltime // 当地时区的时间: 01:23:23 Lmicroseconds // 微秒精度: 01:23:23.123123. 假设是Ltime Llongfile // 完整的文件名和行号: /a/b/c/d.go:23 Lshortfile // 最终文件名元素和行号: d.go:23. 覆盖Llongfile LUTC // 如果设置了Ldate或者Ltime,那么使用UTC而不是本地时区 LstdFlags = Ldate | Ltime // 标准Logger的初始值 ) 这些标志定义了Logger生成的每个日志条目的前缀,(|) 或运算来控制哪些需要输出。无法控制它们出现的顺序(如,此处列出的顺序)或它们呈现的格式(如,注释中所述)。仅当指定Llongfile或Lshortfile时,前缀后跟冒号。查看如下示例: // 设置Ldate | Ltime(或LstdFlags)则产生如下效果 2009/01/23 01:23:23 message // 设置Ldate | Ltime | Lmicroseconds | Llongfile 则产生如下效果 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message 函数Fatal func Fatal(v ...interface{}) Fatal()等效于Print(),然后调用os.Exit(1)。 函数Fatalf func Fatalf(format string, v ...interface{}) Fatal()等效于Printf(),然后调用os.Exit(1)。 函数Fatalln func Fatalln(v ...interface{}) Fatal()等效于Println(),然后调用os.Exit(1)。 函数Flags func Flags() int Flags()返回标准Logger的输出标志。 函数Output func Output(calldepth int, s string) error Output()将记录事件的输出写出来。 字符串s包含要在Logger的flags中指定的前缀之后打印的文本内容。如果s的最后一个字符不是换行符,则会附加换行符。 Calldepth是设置了Llongfile或Lshortfile后,计算文件名和行号时要跳过的帧数; 如果Calldepth的值为1将打印Output()调用者的详细信息。 函数Panic func Panic(v ...interface{}) Panic()等效于Print(),然后调用panic()。 函数Panicf func Panicf(format string, v ...interface{}) Panic()等效于Printf(),然后调用panic()。 函数Panicln func Panicln(v ...interface{}) Panic()等效于Println(),然后调用panic()。 函数Prefix func Prefix() string Prefix()返回标准Logger的输出前缀。 函数Print func Print(v ...interface{}) Print()调用Output()来打印到标准Logger,参数以fmt.Print()的方式处理。 函数Printf func Printf(format string, v ...interface{}) Print()调用Output()来打印到标准Logger,参数以fmt.Printf()的方式处理。 函数Println func Println(v ...interface{}) Print()调用Output()来打印到标准Logger,参数以fmt.Println()的方式处理。 总结几个方法 函数SetFlags func SetFlags(flag int) SetFlags()为标准Logger设置输出标识。 函数SetOutput func SetOutput(w io.Writer) SetOutput()设置标准longer的输出目的地。 函数SetPrefix func SetPrefix(prefix string) SetPrefix()设置标准Logger的输出前缀。 函数New func New(out io.Writer, prefix string, flag int) *Logger New()创建了一个新的Logger。 out设置日志数据的目的地 prefix每行日志记录的前缀 flag定义日志记录操作的属性 类型Logger type Logger struct { // contains filtered or unexported fields } Logger表示一个活跃的日志记录对象,它向io.Writer生成输出。每个日志记录操作只对Writer的Write()方法进行一次调用。Logger可以同时被多个goroutine使用; 它保证对Writer的序列化访问。 例子 var ( buf bytes.Buffer logger = log.New(&buf, "logger: ", log.Lshortfile) ) logger.Print("Hello, log file!") fmt.Print(&buf) // 输出 logger: example_test.go:19: Hello, log file! 方法 (*Logger)Fatal func (l *Logger) Fatal(v ...interface{}) Fatal()等效于l.Print(),然后调用os.Exit(1)。 方法 (*Logger)Fatalf func (l *Logger) Fatalf(format string, v ...interface{}) Fatalf()等效于l.Printf(),然后调用os.Exit(1)。 方法 (*Logger)Fatalln func (l *Logger) Fatalln(v ...interface{}) Fatalln()等效于l.Println(),然后调用os.Exit(1)。 方法 (*Logger)Flags func (l *Logger) Flags() int Flags返回Logger的输出标志。 方法 (*Logger)Output func (l *Logger) Output(calldepth int, s string) error Output写入记录事件的输出。 字符串s包含要在Logger中flags指定的前缀之后打印的文本。如果s的最后一个字符不是换行符,则会附加换行符 Calldepth提供通用的用于恢复PC(程序计数器),当前所有预定义路径上它都是2 样例 var ( buf bytes.Buffer logger = log.New(&buf, "INFO: ", log.Lshortfile) infof = func(info string) { logger.Output(2, info) } ) infof("Hello world") fmt.Print(&buf) // 输出 INFO: example_test.go:36: Hello world 方法(*Logger) Panic func (l *Logger) Panic(v ...interface{}) Panic()等效于l.Print(),然后调用panic()。 方法(*Logger) Panicf func (l *Logger) Panicf(format string, v ...interface{}) Panicf()等效于l.Printf(),然后调用panic()。 方法(*Logger) Panicln func (l *Logger) Panicln(v ...interface{}) Panicln()等效于l.Println(),然后调用panic()。 方法(*Logger) Prefix func (l *Logger) Prefix() string Prefix()返回Logger的输出前缀。 方法(*Logger) Print func (l *Logger) Print(v ...interface{}) Print()调用l.Output()来输出到Logger。参数以fmt.Println()的方式处理。 方法(*Logger) Printf func (l *Logger) Printf(format string, v ...interface{}) Printf()调用l.Output()来输出到Logger。参数以fmt.Printf()的方式处理。 方法(*Logger) Println func (l *Logger) Println(v ...interface{}) Println()调用l.Output()来输出到Logger。参数以fmt.Println()方式处理。 方法(*Logger) SetFlags func (l *Logger) SetFlags(flag int) SetFlags()设置Logger的输出flags。 方法(*Logger) SetOutput func (l *Logger) SetOutput(w io.Writer) SetOutput()设置Logger的输出目的地。 方法(*Logger) SetPrefix func (l *Logger) SetPrefix(prefix string) SetPrefix()设置Logger的输出前缀。 方法(*Logger) Writer func (l *Logger) Writer() io.Writer Writer()返回Logger的输出目的地。

template.md 阅读更多

import "text/template" templage包实现数据驱动的模板以生成文本输出。 要生成HTML输出,请查看html/template包,该软件包具有与此软件包相同的接口,但会自动保护HTML输出免受某些攻击。 Templates通过将模板应用于数据结构来运行。 模板中的注释指的是数据结构的元素(通常是结构体的字段或map中的键),以控制执行并派生要显示的值。 模板执行引擎将遍历结构并设置光标(以句点“.”表示)到结构中当前位置的值。 模板的输入文本是UTF-8编码的任何格式的文本。 动作:数据评估或控制 结构:以“ {{”和“}}”界定 所有动作之外的文本将原样复制到输出中。 除了raw string,动作可能不会跨越换行符,尽管注释可以。 一旦开始解析,可以并行安全地执行模板,如果并行执行共享一个Writer,则输出可以交错。 这是一个简单的示例,输出“ 17 items are made of wool ”。 type Inventory struct { Material string Count uint } sweaters := Inventory{"wool", 17} tmpl, err := template.New("test").Parse("{{.Count}} items are made of {{.Material}}") if err != nil { panic(err) } err = tmpl.Execute(os.Stdout, sweaters) if err != nil { panic(err) } 下面展示更多复杂的示例。 文字和空格 默认情况下,执行模板时,将逐个复制动作之间的所有文本。例如,在上面的示例中,运行程序时,字符串“ items made of ”显示在标准输出上。 但是,为帮助格式化模板源代码,如果操作的左定界符(默认为“{{”)后紧跟一个减号和ASCII空格字符(“{{- ”),则会紧接在前的文本。 同样,如果右定界符(“}}”)前面有一个空格和减号(“ -}}”),则所有紧随其后的空格都将修剪掉。 在这些修饰标记中,必须存在ASCII空格; “{{-3}}”解析为包含数字-3的动作。 例如,执行以下模板: "{{23 -}} < {{- 45}}" // 生成的输出 "23<45" 对于此修剪操作,空格字符的定义与Go中的相同:空格,水平制表符,回车符和换行符。 注释 注释的语法和 Go 语言程序代码中的块注释语法相同,即使用/*和 */ 将注释内容包括起来,例如: {{/* 这是注释内容 */}} 模板中的注释会在模板的解析阶段被剔除,输出时会多出一个空行,就是模板文本中的注释所在的那一行。 根对象 在Go语言的标准库模板中引擎中,点操作符默认指向的是根对象,即Execute函数中的第二个参数,该参数是一个interface{}类型,test/template包提供的文本模板引擎会根据提供的根对象进行底层分析,自动判断以什么形式去理解模板中的语法。 复杂对象 struct 渲染struct对象,如上面的Inventory。使用分隔符包裹起来的内容和Inventory类型中的字段名称要一一对应,且大小写保持一致(Go语言对大小写敏感)。 使用同样的方法调用对象所具有的方法。 map 利用map[string]interface{}类型的根对象,可以实现灵活地向模板添加需要被渲染的子对象。这种方案可行的根本原因在于Go语言中,当interface{}类型作为参数时,调用者可以传入任意类型的值。 定义变量 文本模板引擎支持使用字母数字作为变量的名称,并使用美元符号($)作为前缀,例如$name,在模板中变量的定义语法和程序代码中类似,使用:=连接变量名和赋值语句。 {{$name := "Alice"}} {{$age := 18}} {{$round2 := true}} Name: {{$name}} Age: {{$age}} Round2: {{$round2}} // 输出 Name: Alice Age: 18 Round2: true 注意点 变量定义(或首次获得赋值)必须使用:=的语法 获取变量值时,直接在相应位置使用美元符号加上变量名称即可 所有有关变量的操作都属于模板语法的一部分,因此需要使用双层大括号将其包裹起来 在变量定以后,修改变量的值,直接使用等号即可。 动作 if {{if .yIsZero}} 除数不能为 0 {{else}} {{.result}} {{end}} 在模板使用中,将条件语句(条件语句必须返回一个bool值)放置在if关键字之后,使用空格将它们分隔,并将整个语句使用分隔符{{和}}进行包裹。 {{if pipeline}} T1 {{end}} {{if pipeline}} T1 {{else}} T0 {{end}} {{if pipeline}} T1 {{else if pipeline}} T0 {{end}} range 除了可以在模板中进行条件判断,还可以通过range语句进行迭代操作,直接在模板中对集合类型的数据进行处理和渲染。 Go语言中一般来说有三种类型可以进行迭代操作,数组(Array)、切片(Slice)、字典(Map)。 {{range $name := .Names}} {{$name}} {{end}} // 输出 Alice Bob Carol David {{range $i, $name := .Names}} {{$i}}. {{$name}} {{end}} // 输出 0. Alice 1. Bob 2. Carol 3. David 通过使用语法结构range$index,$value := .Names,可以获得变量的索引和值。就模板语法而言,迭代不同的集合类型没有区别。 {{range pipeline}} T1 {{end}} {{range pipeline}} T1 {{else}} T0 {{end}} with 使用with语句来限定模板渲染的对象范围,对比以下: // 不带with SKU: {{.Inventory.SKU}} Name: {{.Inventory.Name}} UnitPrice: {{.Inventory.UnitPrice}} Quantity: {{.Inventory.Quantity}} // 带with {{with .Inventory}} SKU: {{.SKU}} Name: {{.Name}} UnitPrice: {{.UnitPrice}} Quantity: {{.Quantity}} {{end}}{{with pipeline}} T1 {{end}} {{with pipeline}} T1 {{else}} T0 {{end}} 作用域 和程序代码中的作用域相似,文本密保引擎中也有作用域的概念,with语句是作用域最直接的体现。 {{$name1 := "alice"}} name1: {{$name1}} {{with true}} {{$name1 = "alice2"}} {{$name2 := "bob"}} name2: {{$name2}} {{end}} name1 after with: {{$name1}} // 输出 name1: alice name2: bob name1 after with: alice2 在进入with代码库之前,name1的值为alice,但在with代码块中被修改成了alice2,这个赋值操作直接修改了在模板中全局作用域中定义的模板变量name1的值。 如果在模板末尾增加name2 after with: {{$name2}},那么运行会报错Parse: template: test:10: undefined variable "$name2",模板引擎在解析阶段就发现名为 $name2 的模板变量在 with 代码块之外是属于未定义的,这和在程序代码中操作一个超出作用域的变量是一致的。 注意点: 模板变量name1是在模板的全局作用域中定义的 模板变量name1是在with代码块中进行单纯的赋值操作,即=不是:= 模板变量name2是在with代码的作用域中定义的 {$name1 := "alice"}} name1: {{$name1}} {{with true}} {{$name1 := "alice2"}} {{$name2 := "bob"}} name1 in with: {{$name1}} name2: {{$name2}} {{end}} name1 after with: {{$name1}} // 输出 name1: alice name1 in with: alice2 name2: bob name1 after with: alice 在模板中使用 := 的时候,模板引擎会在当前作用域内新建一个同名的模板变量(等同于程序代码中本地变量和全局变量的区别),在同个作用域内对这个模板变量的操作都不会影响到其它作用域。 除了with语句,if语句和range语句都会在各自的代码块中形成一个局部的作用域。 函数 在执行期间会在两个函数Map中查找函数: 在模板中 在全局函数Map中 默认情况下,模板中未定义任何函数,但可以使用Funcs方法添加它们。 自定义函数 tmpl := template.New("test").Funcs(template.FuncMap{ "add": func(a, b int) int { return a + b }, }) _, err := tmpl.Parse(` result: {{add 1 2}}`) // 输出 result: 3 Funcs方法接受一个template.FuncMap类型的参数,其用法和map类型作为根对象一样,底层也是map[string]interface{},通过这种方法,就可以向模板中添加更多的函数与满足需求。 标准库中的内置函数参见下面的预定义函数。 预定义函数 预定义的全局函数命名如下。 and // 通过返回第一个空的参数或最后一个参数,来返回参数的逻辑与的结果 // 即,“and x y”的行为类似于“ if x then y else x”。 对所有参数进行求值。 call // 返回调用第一个参数的结果,该参数必须是一个函数,其余参数作为它的参数。 // 因此,“call X.Y 1 2”在Go表示法中是 .X.Y(1,2),其中Y是函数值字段,map条目等。 // 第一个参数必须是产生函数类型值的评估结果(不同于诸如print之类的预定义函数)。 // 该函数必须返回一个或两个结果值,其中第二个是error类型。 // 如果参数不匹配该函数,或者返回的错误值为非nil,则执行停止。 html // 返回与其参数的文本表示形式等效的转义HTML。 // 此功能在html/template中不可用,但有一些例外。 index // 返回通过后续参数索引其第一个参数的结果。 // 因此,按照Go语法中: // “index x 1 2 3”是x [1] [2] [3] // 每个索引项目必须是map,切片或数组 slice // slice返回将其第一个参数与其余参数相切片的结果。 // 因此,按照Go语法: // “ slice x 1 2”是x [1:2] // “ slice x”是x [:] // “ slice x 1”是x [1:] // “ slice x 1 2 3” “是x [1:2:3] // 第一个参数必须是字符串,切片或数组。 js // 返回等效于其参数的文本表示形式的转义JavaScript。 len // 返回其参数的整数长度。 not // 返回其单个参数的逻辑反。 or // 通过返回第一个非空参数或最后一个参数,来返回其参数的逻辑或的结果, // 即“or x y”的行为类似于“if x then x else y”。 对所有参数进行求值。 print // fmt.Sprint的别名 printf // fmt.Sprintf的别名 println // fmt.Sprintln的别名 urlquery // 以适合嵌入URL查询的形式返回其参数的文本表示形式的转义值。 // 此功能在html/template中不可用,但有一些例外。 用于等式与不等式判断的函数主要有以下6个,都接收两个分别名为arg1和arg2的参数: eq(equal):当等式 arg1 == arg2 成立时,返回 true,否则返回 false ne(not equal):当不等式 arg1 != arg2 成立时,返回 true,否则返回 false lt(less than):当不等式 arg1 < arg2 成立时,返回 true,否则返回 false le(less than or equal):当不等式 arg1 <= arg2 成立时,返回 true,否则返回 false gt(greater than):当不等式 arg1 > arg2 成立时,返回 true,否则返回 false ge(greater than or equal):当不等式 arg1 >= arg2 成立时,返回 true,否则返回 false 在Go语言中,函数的调用都是以 函数名称(参数1,参数2,...) 的形式,在模板引擎中可以在语法上省略括号。 {{$name1 := "alice"}} {{$name2 := "bob"}} {{$age1 := 18}} {{$age2 := 23}} {{if eq $age1 $age2}} 年龄相同 {{else}} 年龄不相同 {{end}} {{if ne $name1 $name2}} 名字不相同 {{end}} {{if gt $age1 $age2}} alice 年龄比较大 {{else}} bob 年龄比较大 {{end}} // 输出 年龄不相同 名字不相同 bob 年龄比较大 管道 文本模板引擎中也实现了和Unix操作系统一样的管道操作,使用上述add函数进行展示: result: {{add 1 3 | add 2 | add 2}} // 输出 result: 8 模板复用 tmpl := template.New("test").Funcs(template.FuncMap{ "join": strings.Join, }) {{define "list"}} {{join . ", "}} {{end}} Names: {{template "list" .names}} // 输出 Names: Alice, Bob, Cindy, David 注意点: 通过Funcs方法添加了名为join模板函数,实际上是调用string.join 通过define”<名称>“的语法定义一个局部模板,以根对象.作为参数调用join模板函数 通过template"<名称>"<参数>的语法,调用名为list的局部模板,并将,names作为参数传递进去(传递的参数会成为局部模板的根对象) 从本地文件中加载模板 模板内容都硬编码在程序代码中,每次修改都需要重新编译和运行程序,很麻烦也不利于管理,可以将模板内容保存在本地文件中,然后在程序中加载对应的模板后进行渲染。 tmpl, err := template.ParseFiles("template_local.tmpl") 在同个目录创建一个名为template_local.tmpl的模板文件,文件后缀名为.tpl或.tmpl,文件内容如下: {{range .names}} - {{.}} {{end}} template.ParseFiles接收变长的参数,可以同时指定多个模板文件,需要渲染指定的文件时,使用.ExecuteTemplate函数,如下: err = tmpl.ExecuteTemplate(w, "template_local.tmpl", map[string]interface{}{ "names": []string{"Alice", "Bob", "Cindy", "David"}, }) func HTMLEscape func HTMLEscape(w io.Writer, b []byte) HTMLEscape将等同于纯文本数据b的转义HTML写入w。 func HTMLEscapeString func HTMLEscapeString(s string) string HTMLEscapeString返回等效于纯文本数据s的转义HTML。 func HTMLEscaper func HTMLEscaper(args ...interface{}) string HTMLEscaper返回与args的文本表示形式等效的转义HTML。 func IsTrue func IsTrue(val interface{}) (truth, ok bool) IsTrue报告val是否为“true”(不是其类型的零),以及该val是否具有有意义的真值。这是if和其他此类操作使用的true定义。 func JSEscape func JSEscape(w io.Writer, b []byte) JSEscape将等同于纯文本数据b的转义JavaScript写入w。 func JSEscapeString func JSEscapeString(s string) string JSEscapeString返回等效于纯文本数据s的转义JavaScript。 func JSEscaper func JSEscaper(args ...interface{}) string SEscaper返回等效于args的文本表示形式的转义JavaScript。 func URLQueryEscaper func URLQueryEscaper(args ...interface{}) string URLQueryEscaper以适合嵌入URL查询的形式返回其参数的文本表示形式的转义值。 type ExecError type ExecError struct { Name string // Name of template. Err error // Pre-formatted error. } ExecError是Execute在评估其模板出错时返回的自定义错误类型。 (如果发生写错误,则返回实际错误;它不会属于ExecError类型。) func (ExecError) Error func (e ExecError) Error() string func (ExecError) Unwrap func (e ExecError) Unwrap() error type FuncMap type FuncMap map[string]interface{} FuncMap是定义从名称到函数的Map的映射类型。 每个函数必须具有单个返回值, 或者具有两个返回值,其中第二个是error类型。在这种情况下,如果第二个(错误)返回值在执行过程中评估为non-nil,则执行终止,并且Execute返回该错误。 当模板引擎调用带有参数列表的函数时,该参数列表必须是可指派给该函数的参数类型。 适用任意类型参数的函数可以使用interface{}或reflect.Value类型的参数。 返回任意类型结果的函数可以返回interface{}或reflect.Value类型的返回值。 type Template type Template struct { name string *parse.Tree *common leftDelim string rightDelim string } Template表示一个已被解析的模板。 *parse.Tree字段仅导出供html/template使用,应被所有其他客户端视为未导出。 样例 Basic // 定义一个模板 const letter = ` Dear {{.Name}}, {{if .Attended}}It was a pleasure to see you at the wedding. {{- else}}It is a shame you couldn't make it to the wedding. {{- end}}{{with .Gift -}}Thank you for the lovely {{.}}. {{end}}Best wishes, Josie ` // 准备一些数据以插入模板 type Recipient struct { Name, Gift string Attended bool } var recipients = []Recipient{ {"Aunt Mildred", "bone china tea set", true}, {"Uncle John", "moleskin pants", false}, {"Cousin Rodney", "", false}, } // 创建一个template对象并将常量letter解析给它 t := template.Must(template.New("letter").Parse(letter)) // 对每一个recipient执行模板 for _, r := range recipients { err := t.Execute(os.Stdout, r) if err != nil { log.Println("executing template:", err) } } // 输出 Dear Aunt Mildred, It was a pleasure to see you at the wedding. Thank you for the lovely bone china tea set. Best wishes, Josie Dear Uncle John, It is a shame you couldn't make it to the wedding. Thank you for the lovely moleskin pants. Best wishes, Josie Dear Cousin Rodney, It is a shame you couldn't make it to the wedding. Best wishes, Josie Block const ( master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` overlay = `{{define "list"}}{{join . ", "}}{{end}}` ) var ( funcs = template.FuncMap{"join": strings.Join} guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} ) masterTmpl, err := template.New("master").Funcs(funcs).Parse(master) if err != nil { log.Fatal(err) } overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) if err != nil { log.Fatal(err) } if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { log.Fatal(err) } // 输出 Names: - Gamora - Groot - Nebula - Rocket - Star-Lord Names: Gamora, Groot, Nebula, Rocket, Star-Lord Func 本示例演示了用于处理模板文本的自定义函数。它使用strings.Title函数,并使用它使标题文本在模板的输出中看起来不错。 // 首先,创建一个FuncMap用来注册函数 funcMap := template.FuncMap{ // “title”是在模板文本中将调用的函数 "title": strings.Title, } // 一个简单的模板定义来测试函数 // 通过几种方式打印输入文本: // - 原版输出 // - 调用title函数 // - 调用title函数然后以%q输出 // - 以%q输出然后调用title函数 const templateText = ` Input: {{printf "%q" .}}Output 0: {{title .}}Output 1: {{title . | printf "%q"}}Output 2: {{printf "%q" . | title}}` // 创建一个模板,然后添加函数,并解析文本 tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText) if err != nil { log.Fatalf("parsing: %s", err) } // 运行模板来验证输出 err = tmpl.Execute(os.Stdout, "the go programming language") if err != nil { log.Fatalf("execution: %s", err) } // 输出 Input: "the go programming language" Output 0: The Go Programming Language Output 1: "The Go Programming Language" Output 2: "The Go Programming Language" Glob 从目录加载一组模板。 // 创建一个临时目录并使用示例模板定义填充该目录 // 通常,模板文件将已经存在与程序已知的某个位置 dir := createTestDir([]templateFile{ // T0.tmpl 是一个纯模板文件仅调用T1 {"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`}, // T1.tmpl 定义一个模板, T1 调用 T2 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, // T2.tmpl 定义一个模板 T2. {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, }) // 测试后清除目录 defer os.RemoveAll(dir) // pattern是用于查找所有模板文件的全局模式 pattern := filepath.Join(dir, "*.tmpl") // T0.tmpl 是第一个匹配的名字 ,因此它成为起始模板即ParseGlob的返回值 tmpl := template.Must(template.ParseGlob(pattern)) err := tmpl.Execute(os.Stdout, nil) if err != nil { log.Fatalf("template execution: %s", err) } // 输出 T0 invokes T1: (T1 invokes T2: (This is T2)) Helper 此示例演示了一种共享模板并在不同上下文中使用它们的方法。在此变体中,我们将多个驱动程序模板手动添加到现有的模板包中。 // 创建一个临时目录并使用示例模板定义填充该目录 // 通常,模板文件将已经存在与程序已知的某个位置 dir := createTestDir([]templateFile{ // T1.tmpl定义一个模板, T1 调用 T2. {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, // T2.tmpl 定义模板 T2. {"T2.tmpl", `{{define "T2"}}This is T2{{end}}`}, }) // 测试后清除目录 defer os.RemoveAll(dir) // pattern是用于查找所有模板文件的全局模式 pattern := filepath.Join(dir, "*.tmpl") // 加载帮助程序 templates := template.Must(template.ParseGlob(pattern)) // 添加一个驱动程序模板;用一个明确的模板定义来做到这一点 _, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}") if err != nil { log.Fatal("parsing driver1: ", err) } // 添加另一个驱动程序模板 _, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}") if err != nil { log.Fatal("parsing driver2: ", err) } // 在执行之前加载所有模板,text/template包不需要这种操作 // 但是html/template包的转义需要这样的操作,这是一个好习惯 err = templates.ExecuteTemplate(os.Stdout, "driver1", nil) if err != nil { log.Fatalf("driver1 execution: %s", err) } err = templates.ExecuteTemplate(os.Stdout, "driver2", nil) if err != nil { log.Fatalf("driver2 execution: %s", err) } // 输出 Driver 1 calls T1: (T1 invokes T2: (This is T2)) Driver 2 calls T2: (This is T2) Share 本示例演示如何将一组驱动程序模板与不同的帮助程序模板集一起使用。 // 创建一个临时目录并使用示例模板定义填充该目录 // 通常,模板文件将已经存在与程序已知的某个位置 dir := createTestDir([]templateFile{ // T0.tmpl 是一个纯模板文件仅调用 T1. {"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"}, // T1.tmpl 定义一个模板, T1 调用 T2. 注意 T2 并没有定义 {"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`}, }) // 测试后清空目录 defer os.RemoveAll(dir) // pattern是用于查找所有模板文件的全局模式 pattern := filepath.Join(dir, "*.tmpl") // 加载驱动程序 drivers := template.Must(template.ParseGlob(pattern)) // 必须定义T2模板的实现,首先克隆驱动程序,然后将T2的定义添加到模板名称空间 // 1. 克隆帮助程序集,以创建一个新的名称空间来运行它们 first, err := drivers.Clone() if err != nil { log.Fatal("cloning helpers: ", err) } // 2. 定义 T2, version A, 并解析它 _, err = first.Parse("{{define `T2`}}T2, version A{{end}}") if err != nil { log.Fatal("parsing T2: ", err) } // 使用不同版本的T2重复上述过程 // 1. 克隆驱动程序 second, err := drivers.Clone() if err != nil { log.Fatal("cloning drivers: ", err) } // 2. 定义 T2, version B, 并解析它 _, err = second.Parse("{{define `T2`}}T2, version B{{end}}") if err != nil { log.Fatal("parsing T2: ", err) } // 以相反的顺序执行模板,以验证第一个模板不受第二个模板的影响。 err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second") if err != nil { log.Fatalf("second execution: %s", err) } err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first") if err != nil { log.Fatalf("first: execution: %s", err) } Output: T0 (second version) invokes T1: (T1 invokes T2: (T2, version B)) T0 (first version) invokes T1: (T1 invokes T2: (T2, version A)) func Must func Must(t *Template, err error) *Template Must是一个帮助程序,它包装返回(*Template,error)的函数的调用,如果错误为非nil,则会出现恐慌。它旨在用于变量初始化,例如 var t = template.Must(template.New("name").Parse("text")) func New func New(name string) *Template New使用给定名称分配新的未定义模板。 func ParseFiles func ParseFiles(filenames ...string) (*Template, error) ParseFiles创建一个新的模板,并从指定文件中解析模板定义。 返回的模板名称将具有第一个文件的基本名称和已解析的内容。 必须至少有一个文件。 如果发生错误,解析将停止并且返回的*Template为nil。 当在不同目录中解析具有相同名称的多个文件时,最后一个文件将是结果文件。例如,ParseFiles(“a/foo”,“b/foo”)将“ b/foo”存储为名为“foo”的模板,而“a/foo”不可用。 func ParseGlob func ParseGlob(pattern string) (*Template, error) ParseGlob创建一个新的模板,并从该pattern标识的文件中解析模板定义。 这些文件根据filepath.Match的语义进行匹配,并且该模式必须匹配至少一个文件。 返回的模板将具有该模式匹配的第一个文件的(基本)名称和(解析的)内容。 ParseGlob等效于使用模式匹配的文件列表调用ParseFiles。 当在不同目录中解析具有相同名称的多个文件时,最后一个文件将是结果文件。 func (*Template) AddParseTree func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) AddParseTree添加具有指定名称的模板的解析树,并将其与t关联。如果该模板尚不存在,它将创建一个新模板。如果模板确实存在,它将被替换。 func (*Template) Clone func (t *Template) Clone() (*Template, error) Clone返回模板的副本,包括所有关联的模板。 不会复制实际的表示形式,但是会复制关联模板的命名空间,因此在副本中进一步调用Parse会将模板添加到副本中,而不是原始模板。 Clone可用于准备通用模板,并将其与其他模板的变体定义一起使用,方法是在完成克隆后添加变体。 func (*Template) DefinedTemplates func (t *Template) DefinedTemplates() string DefinedTemplates返回一个字符串,其中列出了已定义的模板,并以字符串“;”作为前缀。如果没有,则返回空字符串。用于在此处和html/template中生成错误消息。 func (*Template) Delims func (t *Template) Delims(left, right string) *Template Delims将动作定界符设置为指定的字符串,以在后续对Parse,ParseFiles或ParseGlob的调用中使用。 嵌套模板定义将继承设置。 空定界符代表相应的默认值:{{或}}。 返回值是template,因此可以链式调用。 func (*Template) Execute func (t *Template) Execute(wr io.Writer, data interface{}) error Execute将已解析的模板应用于指定的数据对象,并将输出写入wr。 如果执行模板或写入其输出时发生错误,则执行将停止,但是可能已将部分结果写入Writer。 模板可以安全地并行执行,如果并行执行共享一个Writer,则输出可能会交错。 如果数据是reflect.Value,则该模板将应用于reflect.Value所持有的具体值,如fmt.Print中所示。 func (*Template) ExecuteTemplate func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error ExecuteTemplate将指定名称的与t关联的模板应用于指定的数据对象,并将输出写入wr。 如果执行模板或写入其输出时发生错误,则执行将停止,但是可能已将部分结果写入输出写入器。 模板可以安全地并行执行,如果并行执行共享一个Writer,则输出可能会交错。 func (*Template) Funcs func (t *Template) Funcs(funcMap FuncMap) *Template Funcs将参数映射的元素添加到模板的FuncMap。 必须在解析模板之前调用它。 如果映射中的值不是具有适当返回类型的函数,或者该名称不能在语法上用作模板中的函数,则它会返回恐慌。 覆盖Map元素是合法的。 返回值是Template,因此可以链式调用。 func (*Template) Lookup func (t *Template) Lookup(name string) *Template 查找将返回与t关联的给定名称的模板。如果没有这样的模板或模板没有定义,则返回nil。 func (*Template) Name func (t *Template) Name() string Name返回模板的名称。 func (*Template) New func (t *Template) New(name string) *Template New分配与给定模板和相同定界符关联的新的未定义模板。该关联是可传递的,它允许一个模板通过{{template}}动作来调用另一个模板。 由于关联的模板共享基础数据,因此无法安全并行地进行模板构建。模板一旦构建,就可以并行执行。 func (*Template) Option func (t *Template) Option(opt ...string) *Template Option设置模板的选项。选项由字符串(简单字符串或“key=value”)描述。选项字符串中最多可以有一个等号。如果选项字符串无法识别或无效,则返回恐慌。 已知选项: missingkey:使用Map中不存在的键索引了Map,来控制执行期间的行为。 "missingkey=default" or "missingkey=invalid" // default的行为:什么也不做继续执行 // 如果输出,索引操作的值是"<no value>"字符串 "missingkey=zero" // 该操作返回Map类型元素的零值 "missingkey=error" // 执行立即停止并返回错误 func (*Template) Parse func (t *Template) Parse(text string) (*Template, error) Parse将文本解析为t的模板主体。文本中的命名模板定义({{define ...}}或{{block ...}}语句)定义了与t关联的其他模板,并从t本身的定义中删除。 sudo 可以在连续调用Parse中重新定义模板。 具有仅包含空白和注释的主体的模板定义被认为是空的,不会替换现有模板的主体。 这允许使用Parse添加新的命名模板定义,而不会覆盖主模板主体。 func (*Template) ParseFiles func (t *Template) ParseFiles(filenames ...string) (*Template, error) ParseFiles解析指定的文件,并将生成的模板与t关联。 如果发生错误,则解析停止,返回的模板为nil; 否则为t。 必须至少有一个文件。 由于由ParseFiles创建的模板是由参数文件的基本名称命名的,因此t通常应具有文件(基本)名称之一的名称。 如果不是,则根据t的内容,在调用ParseFiles之前,t.Execute可能会失败。 在这种情况下,请使用t.ExecuteTemplate执行有效的模板。 当在不同目录中解析具有相同名称的多个文件时,最后一个将是结果文件。 func (*Template) ParseGlob func (t *Template) ParseGlob(pattern string) (*Template, error) ParseGlob解析pattern识别的文件中的模板定义,并将结果模板与t关联。 这些文件根据filepath.Match的语义进行匹配,并且该模式必须匹配至少一个文件。 ParseGlob等效于使用模式匹配的文件列表调用t.ParseFiles。 当在不同目录中解析具有相同名称的多个文件时,最后一个文件将是结果文件。 func (*Template) Templates func (t *Template) Templates() []*Template Templates返回与t关联的已定义模板的切片。