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)
}