# 4.01 课后复习-Server

本节课工程结构:

```
(base) yanglei@yuanhong v4-rc % tree ./
./

0 directories, 0 files
```

## PART1. Server

### 1.1 接口定义

`serverInterface.go`:

```go
package v4_rc

import "net/http"

// ServerInterface 服务器实体接口
// 用于定义服务器实体的行为
type ServerInterface interface {
	// Handler 组合http.Handler接口
	http.Handler
	// Start 启动服务器
	Start(addr string) error
}
```

这里组合`http.Handler`,是为了最终调用`http.Serve()`,使得该方法的第2个参数是我们自己实现的`http.Handler`接口的实现.这一点我当时整理笔记时其实是不理解的,我复习时也发现我解释不清楚这件事.故补充.

### 1.2 实现接口的`Start()`方法

#### 1.2.1 实现`Start()`方法

`server.go`:

```go
package v4_rc

import (
	"net"
	"net/http"
)

type Server struct {
}

// ServeHTTP 是http.Handler接口的方法 此处必须先写个实现 不然Server不是http.Handler接口的实现
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	panic("implement me")
}

// Start 启动服务器
func (s *Server) Start(addr string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	return http.Serve(listener, s)
}
```

在`net.Listen()`和`http.Serve()`之间做框架的操作,例如生命周期回调.

#### 1.2.2 测试

`server_test.go`:

```go
package v4_rc

import (
	"testing"
)

// TestServer_Start 测试服务器启动
func TestServer_Start(t *testing.T) {
	s := &Server{}
	err := s.Start(":8081")
	if err != nil {
		t.Fatal(err)
	}
}
```

### 1.3 定义注册路由的方法`addRoute()`

#### 1.3.1 定义`Context`

`context.go`:

```go
package v4_rc

type Context struct {
}
```

这里其实是为了定义`HandleFunc`,而定义`HandleFunc`是为了定义`AddRoute()`.

#### 1.3.2 定义`HandleFunc`

`handle_func.go`

```go
package v4_rc

type HandleFunc func(ctx *Context)
```

#### 1.3.3 在接口上定义`addRoute()`

`server_interface.go`:

```go
package v4_rc

import "net/http"

// ServerInterface 服务器实体接口
// 用于定义服务器实体的行为
type ServerInterface interface {
	// Handler 组合http.Handler接口
	http.Handler
	// Start 启动服务器
	Start(addr string) error

	// addRoute 注册路由
	addRoute(method string, pattern string, handler HandleFunc)
}
```

#### 1.3.4 在实现上定义`addRoute()`

`server.go`:

```go
package v4_rc

import (
	"net"
	"net/http"
)

type Server struct {
}

// ServeHTTP 是http.Handler接口的方法 此处必须先写个实现 不然Server不是http.Handler接口的实现
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	panic("implement me")
}

// Start 启动服务器
func (s *Server) Start(addr string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	return http.Serve(listener, s)
}

// addRoute 注册路由
func (s *Server) addRoute(method string, pattern string, handler HandleFunc) {
	panic("implement me")
}
```

#### 1.3.5 定义`addRoute()`的衍生方法

或者也可以说是暴露给使用者的方法

`server.go`:

```go
package v4_rc

import (
	"net"
	"net/http"
)

type Server struct {
}

// ServeHTTP 是http.Handler接口的方法 此处必须先写个实现 不然Server不是http.Handler接口的实现
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	panic("implement me")
}

// Start 启动服务器
func (s *Server) Start(addr string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	return http.Serve(listener, s)
}

// addRoute 注册路由
func (s *Server) addRoute(method string, pattern string, handler HandleFunc) {
	panic("implement me")
}

// GET 注册GET路由
func (s *Server) GET(path string, handler HandleFunc) {
	s.addRoute(http.MethodGet, path, handler)
}

// POST 注册POST路由
func (s *Server) POST(path string, handler HandleFunc) {
	s.addRoute(http.MethodPost, path, handler)
}
```

## PART2. 完成Server时的工程结构

```
(base) yanglei@yuanhong v4-rc % tree ./
./
├── context.go
├── handle_func.go
├── server.go
├── server_interface.go
└── server_test.go

0 directories, 5 files
```

## 附录

### 1. 可以魔改的点

* 将addr作为Server的一个成员属性
* 我看原生的`http.Server`结构体为了支持HTTPS,组合了一个`*tls.Config`,可以尝试


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://go.sai.show/part04.-ke-hou-fu-xi/4.01-ke-hou-fu-xi-server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
