Go 基础语法3(Socket、httpserver)

10. Socket 服务端和客户端;

10.1 创建简单 Socket 服务端和客户端代码;

网络模型:
在这里插入图片描述
Socket

  • Socket 是对 TCP/UDP 封装后提供的一层接口
  • 利用Socket可以 编写服务端和客户端, 从而实现两者互连
  • 不同语言都有相似的 socket 接口支持
    在这里插入图片描述
  • 服务端:文件 /Users/go/src/com.net/myserver/main.go
package main

import (
	"fmt"
	"io"
	"net"
)

func main() {
	// 创建 socket
	lis,err := net.Listen("tcp", "127.0.0.1:8099")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer lis.Close()
	fmt.Println("创建监听成功,等待客户端连接")

	// 阻塞等待客户端连接
	client,err := lis.Accept()
	if err != nil {
		fmt.Println(err)
		return
	}
	defer client.Close()

	for {
		buf := make([]byte, 512)	//    如果是 8,则截断输出为:读取到8,内容是:i am pro读取到7,内容是:grammer
		n, err := client.Read(buf)
		if err != nil{
			if err == io.EOF{
				break
			}
			fmt.Println(err)
			return
		}
		fmt.Printf("读取到%d,内容是:%s",n,string(buf))
		// 创建监听成功,等待客户端连接
		// 读取到15,内容是:i am programmer
	}
}
  • 客户端:文件 /Users/go/src/com.net/myclient/main.go
package main

import (
	"fmt"
	"net"
)

func main() {
	conn,err := net.Dial("tcp","127.0.0.1:8099")
	if err != nil{
		fmt.Println(err)
		return
	}
	defer conn.Close()

	conn.Write([]byte("i am programmer"))
}

运行配置
在这里插入图片描述

10.2 "死循环"Socket服务端、支持浏览器输出;

  • 服务端改造死循环:文件 /Users/go/src/com.net/myserver/main.go
package main

import (
	"fmt"
	"io"
	"net"
)

func main() {
	// 创建 socket
	lis,err := net.Listen("tcp", "127.0.0.1:8099")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer lis.Close()
	fmt.Println("创建监听成功,等待客户端连接")

	// 服务端死循环,不会结束
	for {
		// 阻塞等待客户端连接
		client,err := lis.Accept()
		if err != nil {
			fmt.Println(err)
			return
		}
		// 单进程处理、放入匿名函数
		func (c net.Conn) {
			defer c.Close()

			buf := make([]byte, 4096)
			n, err := c.Read(buf)
			if err != nil{
				fmt.Println(err)
				return
			}
			fmt.Printf(string(buf[0:n]))	// 切片显示,或者 buf[:n]
		}(client)	// 传入 client

	}

}

浏览器输出
在这里插入图片描述

  • 服务端:文件 /Users/go/src/com.net/myserver/main.go
package main

import (
	"fmt"
	"net"
)

// 写死一个字符串
func response() string {
	str:=`HTTP/1.1 200 OK
Server: myserver
Content-Type: text/html

this is body
`
	return str
}

func main() {
	// 创建 socket
	lis,err := net.Listen("tcp", "127.0.0.1:8099")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer lis.Close()
	fmt.Println("创建监听成功,等待客户端连接")

	// 服务端死循环,不会结束
	for {
		// 阻塞等待客户端连接
		client,err := lis.Accept()
		if err != nil {
			fmt.Println(err)
			return
		}
		// 单进程处理、放入匿名函数
		func (c net.Conn) {
			defer c.Close()

			buf := make([]byte, 4096)
			n, err := c.Read(buf)
			if err != nil{
				fmt.Println(err)
				return
			}
			fmt.Printf(string(buf[0:n]))	// 切片显示,或者 buf[:n]
			c.Write([]byte(response()))

		}(client)	// 传入 client

	}
}
  • 客户端:文件 /Users/go/src/com.net/myclient/main.go
package main

import (
	"fmt"
	"net"
)

func main() {
	conn,err := net.Dial("tcp","127.0.0.1:8099")
	if err != nil{
		fmt.Println(err)
		return
	}
	defer conn.Close()

	conn.Write([]byte("i am programmer!"))

	buf := make([]byte, 4096)
	n, err := conn.Read(buf)
	if err != nil{
		fmt.Println(err)
		return
	}
	fmt.Printf(string(buf[0:n]))
}

10.3 正则入门、分析请求path、Socket服务端开启协程支持;

正则:

// 所属包:regexp
r,err := regexp.Compile(expr string) (*Regexp, error) // 将正则表达式编译成一个正则对象
r :=regexp.MustCompile(str string) *Regexp // 同上,如果正则写错了,会把异常panic出来
r.MatchString(s string) bool  // 判断能否匹配到(一般做判断用,判断如果没有,就不做下面的步骤)
r.FindStringSubmatch
r.FindAllStringSubmatch
// 前者查找匹配到的第一个匹配结果及分组内容,后者支持多个匹配结果,n参数(查找多少次,负数为不限)
  • 文件 /Users/go/src/com.net/mytest/main.go
package main

import (
	"fmt"
	"regexp"
)

func GetRqPath(rq string) string {
	r := regexp.MustCompile(`^GET\s(.*?)\sHTTP`)	// 一个空格\
	if r.MatchString(rq) {
		return r.FindStringSubmatch(rq)[1]	// 取第一个匹配
	} else {
		return "/"
	}
}

func main() {
	str:=`GET /abc.php HTTP/1.1
Host: localhost:8099
Connection: keep-alive
Upgrade-Insecure-Requests: 1`

	fmt.Println(GetRqPath(str))
}

分析请求 path

  • 文件 /Users/go/src/com.net/myserver/netutil.go
package main

import "regexp"

func GetRqPath(rq string) string {
	r := regexp.MustCompile(`^GET\s(.*?)\sHTTP`)	// 一个空格\
	if r.MatchString(rq) {
		return r.FindStringSubmatch(rq)[1]	// 取第一个匹配
	} else {
		return "/"
	}

}
  • 服务端:文件 /Users/go/src/com.net/myserver/main.go
package main

import (
	"fmt"
	"net"
	"runtime"
	"time"
)

// 写死一个字符串
func response() string {
	str:=`HTTP/1.1 200 OK
Server: myserver
Content-Type: text/html

this is body
`
	return str
}

func main() {
	// 创建 socket
	lis,err := net.Listen("tcp", "127.0.0.1:8099")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer lis.Close()
	fmt.Println("创建监听成功,等待客户端连接")
	// *获取当前进程数
	go func() {
		for{
			fmt.Printf("当前任务数:%d\n",runtime.NumGoroutine())
			time.Sleep(time.Second*2)

		}
	}()

	// 服务端死循环,不会结束
	for {
		// 阻塞等待客户端连接
		client,err := lis.Accept()
		if err != nil {
			fmt.Println(err)
			return
		}
		// *使用协程处理
		go func (c net.Conn) {
			defer c.Close()

			buf := make([]byte, 4096)
			n, err := c.Read(buf)
			if err != nil{
				fmt.Println(err)
				return
			}
			// *休眠 5 秒
			if GetRqPath(string(buf[0:n])) == "/delay" {
				time.Sleep(time.Second*5)
			}
			// fmt.Printf(string(buf[0:n]))	// 切片显示,或者 buf[:n]
			c.Write([]byte(response()))

		}(client)	// 传入 client

	}
}

10.4 实现浏览器静态文件的访问、处理 404;

在这里插入图片描述

  • 文件 /Users/go/src/com.net/myserver/netutil.go
package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
)

func GetRequestPath(rq string) string {
	r := regexp.MustCompile(`^GET\s(.*?)\sHTTP`)	// 一个空格\
	if r.MatchString(rq) {
		return r.FindStringSubmatch(rq)[1]	// 取第一个匹配
	} else {
		return "/"
	}

}


func response(body []byte, status HttpStatus) string {
	str:=`HTTP/1.1 %d %s
Server: myserver
Content-Type: text/html

%s
`
	ret:= fmt.Sprintf(str, status.Code, status.Message, body)
	return ret
}

// 判断文件是否存在
func ExistsFile(path string) (bool,error)  {
	_,err:=os.Stat("./web"+path)
	if err == nil {
		return true,nil
	}else{
		if os.IsNotExist(err) { //不存在
			return false,nil
		} else {
			return false,err
		}
	}
}

func ReadHtml(path string) string  {
	exist, _ := ExistsFile(path)
	if exist {

		file, _ := ioutil.ReadFile("./web"+path)
		return response(file, NewHttpStatus(200,"OK"))
	}else{
		return response([]byte("404"),NewHttpStatus(404,"Not Found"))
	}
}
  • 文件 /Users/go/src/com.net/myserver/status.go
package main

type HttpStatus struct {
	Code int
	Message string
}

func NewHttpStatus(code int ,message string) HttpStatus  {
	hs:=HttpStatus{code,message}
	return hs
}
  • 文件 /Users/go/src/com.net/web/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
这是首页
</body>
</html>
  • 文件 /Users/go/src/com.net/myserver/main.go
package main

import (
	"fmt"
	"net"
	"runtime"
	"time"
)

func main() {
	// 创建 socket
	lis,err := net.Listen("tcp", "127.0.0.1:8099")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer lis.Close()
	fmt.Println("创建监听成功,等待客户端连接")
	// 获取当前进程数
	go func() {
		for{
			fmt.Printf("当前任务数:%d\n",runtime.NumGoroutine())
			time.Sleep(time.Second*2)

		}
	}()

	// 服务端死循环,不会结束
	for {
		// 阻塞等待客户端连接
		client,err := lis.Accept()
		if err != nil {
			fmt.Println(err)
			return
		}
		// 使用协程处理
		go func (c net.Conn) {
			defer c.Close()

			buf := make([]byte, 4096)
			n, err := c.Read(buf)
			if err != nil{
				fmt.Println(err)
				return
			}
			// 休眠 5 秒
			//if GetRequestPath(string(buf[0:n])) == "/delay" {
			//	time.Sleep(time.Second*5)
			//}
			// fmt.Printf(GetRequestPath(string(buf[0:n])))	// 切片显示,或者 buf[:n]
			// c.Write([]byte(response()))

			c.Write([]byte(ReadHtml(GetRequestPath(string(buf[:n])))))

		}(client)	// 传入 client
	}

}

11. httpserver;

11.1 使用http包快速创建server、自定义handler;

  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("hello"))
	})

	http.HandleFunc("/abc", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("abc"))
	})
	//err := http.ListenAndServe(":8099", nil)  // 第二个参数 nil,则自动生成路由
	//if err != nil {
	//	fmt.Println(err)
	//}

	// 同上
	server := http.Server{Addr: ":8099", Handler: nil}
	err := server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}
}

优化:

package main

import (
	"fmt"
	"net/http"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	writer.Write([]byte("hello,myhandler"))
}



func main() {
	handler := new(MyHandler)
	server := http.Server{Addr: ":8099", Handler: handler}	// Handler 接口
	err := server.ListenAndServe()
	if err != nil {
		fmt.Println(err)
	}
}

11.2 路由、设置cookie、注销、判断登录;

在这里插入图片描述

// 上一章代码:
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
       writer.Write([]byte("hello"))	
 })
http.ListenAndServe(":8099",nil)

// 可以看到 HandleFunc里面有个 
var defaultServeMux ServeMux

// 如果server对象不提供handler,则启用默认ServeMux,这是一个路由管理器

mux:=http.NewServeMux()
mux.Handle("/",new(MyHandler))
 
server:=http.Server{Addr:":8099",Handler:mux}
err:=server.ListenAndServe()
if err!=nil{
	fmt.Println(err)
}
// 假设访问 / 一切OK。如果访问 /admin 则需要登录(判断 cookie 中是否有 usename 这一项)
// 先写登录的路由
  mux.HandleFunc("/login", func(writer http.ResponseWriter, request *http.Request) {
	writer.Write([]byte("这里是登录页面"));
})
// 为了实现登录,我们规定 如果访问的是
/login?username=xxxoo
// 那么就设置 cookie: username=xxxoo(写死值)
// 获取query参数
request.URL.Query().Get("xxoo")  // 如果没有则返回"" (不是nil)

// 设置cookie
c:=&http.Cookie{Name:"username",Value:getusername,Path:"/"}
http.SetCookie(writer,c)
  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"net/http"
	"time"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	// request.URL.Path	// 可获取url
	writer.Write([]byte("hello,myhandler"))
}

func main() {
	// 路由
	mymux := http.NewServeMux()
	// mymux.Handle("/", &MyHandler{})

	// 模拟需求:假设访问/ 一切OK。如果访问/admin则需要登录(判断 cookie 中是否有 usename 这一项)
	mymux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		// 此处可以对路由进行定义
		writer.Write([]byte("index"))
	})

	// 登录
	mymux.HandleFunc("/login", func(writer http.ResponseWriter, request *http.Request){
		getUserName := request.URL.Query().Get("username")
		if getUserName != "" {
			c := &http.Cookie{Name:"username", Value:getUserName, Path:"/"}
			http.SetCookie(writer,c)	// 设置 cookie
		}
		writer.Write([]byte("这里是登录页面"))
	})

	// 退出
	mymux.HandleFunc("/unlogin", func(writer http.ResponseWriter, request *http.Request) {
		c := &http.Cookie{Name:"username", Value:"", Path:"/", Expires:time.Now().AddDate(-1,0,0)}
		http.SetCookie(writer,c)
		// 加入 http 协议头
		writer.Header().Set("Content-type","text/html")
		writer.Write([]byte("unlogin...."));
		script:=`<script>
			setTimeout(()=>{self.location='/'},2000)

</script>`
		writer.Write([]byte(script))
	})

	http.ListenAndServe(":8099", mymux)
}

另:插件化思路

// 嵌套一个函数,好比python中的装饰器模式
func LoginHandler(hander http.Handler) http.Handler{
	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		 ///这里做业务逻辑
	})
}

// 获取cookie
cookie,err:=request.Cookie("username")
if err!=nil || cookie==nil{
	 xxxooo
}

// Redirect
http.Redirect(writer,request,"/login",302)

//
func LoginHandler(hander http.Handler) http.Handler{
	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		cookie,err:=request.Cookie("username")
		if err!=nil || cookie==nil{
			http.Redirect(writer,request,"/login",302)
		}else{
			hander.ServeHTTP(writer,request)
		}
	})
}

11.3 自定义路由、支持 GET / POST 访问;

  • 文件 /Users/go/src/com.net/myhttpserver/core/MyRouter.go
package core

import (
	"net/http"
)

type MyRouter struct {
	Mapping map[string]map[string]http.HandlerFunc
}

func DefaultRouter() *MyRouter {
	return &MyRouter{make(map[string]map[string]http.HandlerFunc)}
}

func(this *MyRouter) Get(path string, f http.HandlerFunc)  {
	if this.Mapping["GET"] == nil{
		this.Mapping["GET"] = make(map[string]http.HandlerFunc)
	}
	this.Mapping["GET"][path] = f
}

func(this *MyRouter) Post(path string, f http.HandlerFunc)  {
	if this.Mapping["POST"] == nil{
		this.Mapping["POST"] = make(map[string]http.HandlerFunc)
	}
	this.Mapping["POST"][path] = f
}

func(this *MyRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request){
	f := this.Mapping[request.Method][request.URL.Path]
	f(writer,request)
}
  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"com.net/myhttpserver/core"
	"net/http"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	// request.URL.Path	// 可获取url
	writer.Write([]byte("hello,myhandler"))
}

func main() {
	router := core.DefaultRouter()

	router.Get("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("get abc"))
	})

	router.Post("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("post abc"))
	})

	http.ListenAndServe(":8099",router)
}

11.4 创建自己的简易"上下文"对象;

  • 文件 /Users/go/src/com.net/myhttpserver/core/MyRouter.go
package core

import (
	"net/http"
)

type MyHandlerFunc func(ctx *MyContext)

type MyRouter struct {
	Mapping map[string]map[string]MyHandlerFunc
	Ctx *MyContext
}

func DefaultRouter() *MyRouter {	// 初始化
	return &MyRouter{make(map[string]map[string]MyHandlerFunc),&MyContext{}}
}

func(this *MyRouter) Get(path string, f MyHandlerFunc)  {
	if this.Mapping["GET"] == nil{
		this.Mapping["GET"] = make(map[string]MyHandlerFunc)
	}
	this.Mapping["GET"][path] = f
}
func(this *MyRouter) Post(path string, f MyHandlerFunc)  {
	if this.Mapping["POST"] == nil{
		this.Mapping["POST"] = make(map[string]MyHandlerFunc)
	}
	this.Mapping["POST"][path] = f
}


func(this *MyRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request){
	this.Ctx.request=request
	this.Ctx.ResponseWriter=writer

	// chrome 会默认请求图标地址
	if f,OK:=this.Mapping[request.Method][request.URL.Path];OK{
		f(this.Ctx)
	}
}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyContext.go
package core

import "net/http"

type MyContext struct {		//上下文对象
	request *http.Request
	http.ResponseWriter
}

func(this *MyContext) WriteString(str string){
	this.Write([]byte(str))
}
  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"com.net/myhttpserver/core"
	"net/http"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	// request.URL.Path	// 可获取url
	writer.Write([]byte("hello,myhandler"))
}

func main() {
	router:=core.DefaultRouter()

	router.Get("/", func(ctx *core.MyContext) {
		ctx.WriteString("my string GET")
	})
	router.Post("/", func(ctx *core.MyContext) {
		ctx.WriteString("my string POST")
	})

	http.ListenAndServe(":8099",router)
}

11.5 "框架"支持控制器雏形;

基本结构:
在这里插入图片描述

  • 文件 /Users/go/src/com.net/myhttpserver/core/MyRouter.go
package core

import (
	"net/http"
)
type MyHandlerFunc func(ctx *MyContext)
type MyRouter struct {
	Mapping map[string]ControllerInterface

}

func DefaultRouter() *MyRouter {
	return &MyRouter{make(map[string]ControllerInterface)}
}

//加入 path 和 Controller 的对应关系
func(this *MyRouter) Add(path string, c ControllerInterface)  {
	this.Mapping[path] = c
}

func(this *MyRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request){
	// chrome 会默认请求图标地址
	if f,OK := this.Mapping[request.URL.Path];OK{
		f.Init(&MyContext{request,writer}) //关键代码
		if request.Method == "GET" {		//没有做防错处理
			f.GET()
		}
		if request.Method == "POST" {	//没有做防错处理
			f.POST()
		}
	}
}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyContext.go
package core

import "net/http"

type MyContext struct {		//上下文对象
	request *http.Request
	http.ResponseWriter
}

func(this *MyContext) WriteString(str string){
	this.Write([]byte(str))
}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyController.go
package core

type MyController struct {
	Ctx *MyContext	// 上下文对象
}

// 初始化
func(this *MyController) Init (ctx *MyContext)  {
	this.Ctx=ctx
}

type ControllerInterface interface {
	Init(ctx *MyContext)
	GET()
	POST()
}

  • 文件 /Users/go/src/com.net/myhttpserver/NewsController.go
package main

import "com.net/myhttpserver/core"

type NewsController struct {
	core.MyController
}

func(this *NewsController) GET()  {
	this.Ctx.WriteString("this is newscontroller")
}

func(this *NewsController) POST()  {
	this.Ctx.WriteString("this is newscontroller for POST")
}
  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"com.net/myhttpserver/core"
	"net/http"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	// request.URL.Path	// 可获取url
	writer.Write([]byte("hello,myhandler"))
}

func main() {
	router:=core.DefaultRouter()
	router.Add("/",&NewsController{})
	http.ListenAndServe(":8099",router)
}

11.6 支持 GET / POST参数、JSON输出和Model映射;

在这里插入图片描述
实现 WriteJSON 功能

// 之前使用第三方包ffjson
// https://github.com/pquerna/ffjson
func(this *MyContext) WriteJSON(m interface{}){
	this.Header().Add("Content-type","application/json")
	result,err:=ffjson.Marshal(m)
	if err!=nil{
		panic(err)
	}
	this.Write(result)
}

处理参数

// 获取GET参数
// 写在MyController中,这不属于上下文的范畴
func(this *MyController) GetParam(paramName string,defValue  ...string) string {
	p:=this.Ctx.request.URL.Query().Get(paramName)
	if p=="" && len(defValue)>0{
		return defValue[0]
	}
	return p
}

// 获取POST参数(简单版)
// 这个代码写在MyController中,这不属于上下文的范畴
func(this *MyController) PostParam(paramName string,defValue  ...string) string {
	p:=this.Ctx.request.PostFormValue(paramName)
	if p=="" && len(defValue)>0{
		return defValue[0]
	}
	return p
}

// 获取JSON参数
// 在Java中,很常见的做法是得到JSON内容映射到模型(Model)里,golang 中我们也可以模拟实现一番
func(this *MyController) JSONParam(obj interface{})  {
	c,err:=ioutil.ReadAll(this.Ctx.request.Body)
	if err!=nil{
		panic(err)
	}
	err=ffjson.Unmarshal(c,obj)
	if err!=nil{
		panic(err)
	}
}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyContext.go
package core

import (
	"github.com/pquerna/ffjson/ffjson"
	"net/http"
)

type MyContext struct {		//上下文对象
	request *http.Request
	http.ResponseWriter
}

func(this *MyContext) WriteString(str string){
	this.Write([]byte(str))
}

// writeJson
func(this *MyContext) WriteJSON(m interface{}){
	this.Header().Add("Content-type","application/json")
	ret,err := ffjson.Marshal(m)
	if err!=nil{
		panic(err)
	}
	this.Write(ret)
}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyRouter.go
package core

import (
	"net/http"
)
type MyHandlerFunc func(ctx *MyContext)
type MyRouter struct {
	Mapping map[string]ControllerInterface

}

func DefaultRouter() *MyRouter {
	return &MyRouter{make(map[string]ControllerInterface)}
}

//加入 path 和 Controller 的对应关系
func(this *MyRouter) Add(path string, c ControllerInterface)  {
	this.Mapping[path] = c
}

func(this *MyRouter) ServeHTTP(writer http.ResponseWriter, request *http.Request){
	// chrome 会默认请求图标地址
	if f,OK := this.Mapping[request.URL.Path];OK{
		f.Init(&MyContext{request,writer}) //关键代码
		if request.Method == "GET" {		//没有做防错处理
			f.GET()
		}
		if request.Method == "POST" {	//没有做防错处理
			f.POST()
		}
	}

}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyUtil.go
package core

// 自定义 map 接口
type Map map[string]interface{}
  • 文件 /Users/go/src/com.net/myhttpserver/core/MyController.go
package core

import (
	"github.com/pquerna/ffjson/ffjson"
	"io/ioutil"
)

type MyController struct {
	Ctx *MyContext	// 上下文对象
}

// 初始化
func(this *MyController) Init (ctx *MyContext)  {
	this.Ctx=ctx
}

type ControllerInterface interface {
	Init(ctx *MyContext)
	GET()
	POST()
}

// 获取GET参数方法
// "..." 不定参数
func(this *MyController) GetParam(key string, defValue ...string) string  {
	ret := this.Ctx.request.URL.Query().Get(key)
	if ret == "" && len(defValue) > 0{
		return defValue[0]
	}
	return ret
}

// 获取POST参数,单参数
func(this *MyController) PostParam(key string, defValue ...string) string  {
	ret := this.Ctx.request.PostFormValue(key)
	if ret == "" && len(defValue) > 0{
		return defValue[0]
	}
	return ret
}

// 获取JSON参数,单参数
func(this *MyController) JSONParam(obj interface{})  {
	body,err := ioutil.ReadAll(this.Ctx.request.Body)
	if err!=nil{
		panic(err)
	}
	err = ffjson.Unmarshal(body,obj)
	if err != nil{
		panic(err)
	}
}

  • 文件 /Users/go/src/com.net/myhttpserver/NewsController.go
package main

import "com.net/myhttpserver/core"

type NewsController struct {
	core.MyController
}

func(this *NewsController) GET()  {
	// this.Ctx.WriteString("this is newscontroller")
	// WriteJSON
	// this.Ctx.WriteJSON(map[string]string{"username" : "hua"})	// 自定义 map 对象
	// this.Ctx.WriteJSON(map[string]string{"username" : "hua"})
	// this.Ctx.WriteJSON(core.Map{"username" : "hua"})
	p:=this.GetParam("username", "no param", "abc")
	this.Ctx.WriteString(p)


}

func(this *NewsController) POST()  {
	// this.Ctx.WriteString("this is newscontroller for POST")

	//p:=this.PostParam("username", "no param for post", "abc")
	//this.Ctx.WriteString(p)

	user := UserModel{}
	this.JSONParam(&user)
	this.Ctx.WriteJSON(user)
}
  • 文件 /Users/go/src/com.net/myhttpserver/UserModel.go
package main

type UserModel struct {
	UserName string
	UserAge int
}
  • 文件 /Users/go/src/com.net/myhttpserver/main.go
package main

import (
	"com.net/myhttpserver/core"
	"net/http"
)

type MyHandler struct {

}

func(*MyHandler) ServeHTTP (writer http.ResponseWriter, request *http.Request){
	// request.URL.Path	// 可获取url
	writer.Write([]byte("hello,myhandler"))
}

func main() {
	router:=core.DefaultRouter()

	router.Add("/",&NewsController{})

	http.ListenAndServe(":8099",router)
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值