[go]net/http

返回数据

- 最简单的http服务

package main

import (
	"net/http"
)

func main() {
	http.ListenAndServe(":8080", nil)
}
  • 返回字符串
- 挂载路由节点
//例1:
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello http"))
	})
	http.ListenAndServe(":8080", nil)
}

//例2
package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "hello world")
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}

//例3:
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "hello world2")
	})
	http.ListenAndServe(":8080", nil)
}
- 启动http接口

package main

import (
	"io"
	"log"
	"net/http"
)

func main() {
	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))
}
  • 返回json
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("content-type", "application/json; charset=utf-8")
		w.Write([]byte(`{"code":-1, "msg":"no such file我"}`))
	})
	http.ListenAndServe(":8080", nil)
}
- 例子: 读取data.json,返回json
- data.json
[
  {
    "name": "mm",
    "age": 22
  }
]


type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

var data []User

func LoadData() {
	var content, err = ioutil.ReadFile("data.json")
	if err != nil {
		fmt.Println(err.Error())
	}

	json.Unmarshal(content, &data)
	fmt.Println(data)
}

func main() {
	LoadData()

	// CRUD endpoint functions
	u := func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(data)// 1.json写入io.Writer/os.Stdout
								       // 2.[普通marshell]json和data之间转换
	}

	http.HandleFunc("/user", u)
	http.ListenAndServe(":8080", nil)
}


获取参数

// GET localhost:8080/?name=mm&age=22
Content-Type: "" //request的Content-Type值为""

//参数携带在了url(Query String Parameters)
name=m1&age=22

// body内容为空

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm() //将参数解析到一个map里

		fmt.Println(r.Form) //map[age:[22] name:[mm]]
		name := r.Form["name"][0]
		
		fmt.Println(name)
		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}
//mm
//GET localhost:8080/?name=m1&name=m2&age=22
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()

		fmt.Println(r.Form) //map[age:[22] name:[m1 m2]]

		name1 := r.Form["name"][0]
		name2 := r.Form["name"][1]

		fmt.Println(name1, name2)
		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}

//m1 m2
// GET localhost:8080/?name=mm&age=22

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		name := r.Form.Get("name") //使用url.Values(map)封装的GET方法取值
		age := r.Form.Get("age")
		fmt.Println(name, age)
		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}
//mm 22
- form提交默认是get.(和GET携带参数处理方式一样)
	<body>
	<form action="http://localhost:8080/">
		<input type="text" name="name">
		<input type="text" name="age">
		<input type="submit">
	</form>
	</body>
	
Content-Type: "" //request的Content-Type值为""


//数据(参数)携带在了url(Query String Parameters ) 
name=admin&age=123456

// body内容为空


func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()       //将参数解析到一个map里
		fmt.Println(r.Form) //map[age:[123456] name:[admin]]

		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}
- 表单请求
	<body>
	<form action="http://localhost:8080/" method="post">
		<input type="text" name="name">
		<input type="text" name="age">
		<input type="submit">
	</form>
	</body>

//默认将request的Content-Type设置为
	Content-Type: application/x-www-form-urlencoded

//将数据携带在了body(Form Data):
name=m1&age=22


func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		body, _ := ioutil.ReadAll(r.Body)
		fmt.Println(string(body)) //name=m1&age=22

		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}

- 上面这种情况,解析表单参数

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		r.ParseForm() //将参数解析到一个map里
		fmt.Println(r.Form) //map[age:[22] name:[mm]]
		io.WriteString(w, "hi")
	})
	http.ListenAndServe(":8080", nil)
}
- 解析post body: json data

POST localhost:8080
Content-Type: application/json;charset=UTF-8

{
  "name": "m1",
  "age": 22
}

// Content-Type: application/json;charset=UTF-8

//数据携带在body(Request Payload)
{"name":"mm","age":22}

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		body, _ := ioutil.ReadAll(r.Body)
		//fmt.Fprintf(w, "%s", body)
		user := User{}
		err := json.Unmarshal(body, &user)
		if err != nil {
			fmt.Println(err)
		}
		fmt.Println(user)
	})
	http.ListenAndServe(":8080", nil)
}

文件上传下载

  • 文件下载
- 简单的web 文件服务
func main() {
	// Simple static webserver:
	log.Fatal(http.ListenAndServe(":3001", http.FileServer(http.Dir("."))))
}

- 伪url访问真实目录
func main() {
	// To serve a directory on disk (/tmp) under an alternate URL
	// path (/tmpfiles/), use StripPrefix to modify the request
	http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("."))))
	http.ListenAndServe(":3001", nil)
}
  • 文件上传
- request:
Content-Type: multipart/form-data;



- 文件上传的表单
Content-Disposition 属性是作为对下载文件的一个标识字段
如果有type=file的话,就要用到multipart/form-data了。
	浏览器会把整个表单以控件为单位分割,
	并为每个部分加上
		Content-Disposition(form-data或者file),
		Content-Type(默认为text/plain),
		name(控件name)等信息,
		
		并加上分割符(boundary)。
		
<body>
<form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit">
</form>
</body>

- 请求body: 内容里Content-Type会自动感知为对应文件类型
------WebKitFormBoundary9Px0BT0GcBlQEiUO
Content-Disposition: form-data; name="file"; filename="app.json"
Content-Type: application/json

{
  "name": "Start on Heroku: Go",
  "description": "Go Getting Started Example App",
  "keywords": [
    "getting-started",
    "go",
    "sample",
    "example"
  ],
  "image": "heroku/go:1.6",
  "mount_dir": "src/github.com/heroku/go-getting-started",
  "website": "http://github.com/heroku/go-getting-started",
  "repository": "http://github.com/heroku/go-getting-started"
}

------WebKitFormBoundary9Px0BT0GcBlQEiUO--



func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		body, _ := ioutil.ReadAll(r.Body)
		fmt.Println(string(body))
		w.Write([]byte("hi"))

		//r.ParseMultipartForm(32 << 20)
		//file, handler, err := r.FormFile("file")
		//if err != nil {
		//	w.WriteHeader(http.StatusInternalServerError)
		//	w.Write([]byte("解析表单出错"))
		//	return
		//}
		//defer file.Close()
		//f, err := os.OpenFile(handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		//if err != nil {
		//	w.WriteHeader(http.StatusInternalServerError)
		//	w.Write([]byte("写入文件出错"))
		//	return
		//}
		//defer f.Close()
		//io.Copy(f, file)
	})
	http.ListenAndServe(":8080", nil)
}

如果传的是图片, 则会展示一些乱码

常用方法

  • 区分http方法: r.Method
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			io.WriteString(w, "get")
		} else if r.Method == "POST" {
			io.WriteString(w, time.Now().Format("post: 2006-01-02 15:04:05"))
		}
	})
	http.ListenAndServe(":8080", nil)
}
- w.Write后面语句会执行
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hi"))
		fmt.Println("123213123")
	})

	http.ListenAndServe(":3000", nil)
}

//return后不再执行
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hi"))
		return
		fmt.Println("123213123")
	})

	http.ListenAndServe(":3000", nil)
}
- 读文件,返回文件
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		data, err := ioutil.ReadFile("./static/view/signup2.html")
		if err != nil {
			w.WriteHeader(http.StatusNotFound)
			w.Write([]byte(err.Error()))
			return
		}
		w.Write(data)
	})

	http.ListenAndServe(":3000", nil)
}
r.Method == "GET"
time.Now().Format("2006-01-02 15:04:05")


//文件操作

os.Create(fileMeta.Location)
io.Copy(newFile, file)
os.Remove(fMeta.Location)

ioutil.ReadFile("./static/view/index.html")
os.Open(fm.Location)
ioutil.ReadAll(f)
newFile.Seek(0, 0)



//获取GET参数
// - 方法1
r.ParseForm()
op := r.Form.Get("op")

// - 方法2
r.ParseForm()
op := r.Form["op"][0]

// 小结: 表单post过来的格式和 get方法通过路径携带参数  提交过来的格式 是一致的.


//获取表单提交字段数据
// - 方法1
r.ParseForm()
op := r.Form.Get("op")

// - 方法2
r.ParseForm()
filehash := r.Form["filehash"][0]

//表单传文件
file, head, err := r.FormFile("file")  // <form action="http://localhost:8081/upload" method="post" enctype="multipart/form-data">


w.Write([]byte("Upload Failed."))
w.Write([]byte(`{"code":-1,"msg":"no such file"}`))
io.WriteString(w, "internel server error")

//设置下载头
w.Header().Set("Content-Type", "application/octect-stream")
w.Header().Set("content-disposition", "attachment; filename=\""+fm.FileName+"\"")


//设置跨域头
w.Header().Set("Access-Control-Allow-Origin", "*")             //允许访问所有域
w.Header().Add("Access-Control-Allow-Headers", "Content-Type") //header的类型
w.Header().Set("content-type", "application/json")

//TODO: 设置全局跨域中间件

w.WriteHeader(http.StatusOK)
w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusMethodNotAllowed)
w.WriteHeader(http.StatusForbidden)

http.Redirect(w, r, "/static/view/home.html", http.StatusFound)


fmt.Println(err.Error())
// http包基础使用

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

})
http.ListenAndServe(":3000", nil)
// http包进阶使用

//初始化路由
mux = http.NewServeMux()
mux.HandleFunc("/job/save", handleJobSave)

//设置静态目录
staticDir = http.Dir(G_config.WebRoot)
staticHandler = http.FileServer(staticDir)
mux.Handle("/", http.StripPrefix("/", staticHandler))

listener, err = net.Listen("tcp", ":" + strconv.Itoa(G_config.ApiPort));

//创建http服务器
httpServer = &http.Server{
    ReadTimeout: time.Duration(G_config.ApiReadTimeout) * time.Millisecond,
    WriteTimeout: time.Duration(G_config.ApiWriteTimeout) * time.Millisecond,
    Handler: mux,
}

go httpServer.Serve(listener)

net/http模块架构

前后端交互数据

通过表单提交

// 前端表单提交

<form action="http://localhost:8000/" method="post">
    <input type="text" name="username">
    <input type="text" name="password">
    <input type="submit">
</form>

//后端接收

r.ParseForm()
username := r.Form.Get("username") //接收到的都是字符串

前端ajax post提交json

// 前端ajax post提交json

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
<div id="app">
    <button @click="postData">postData</button>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="node_modules/axios/dist/axios.js"></script>
<script>
    let vm = new Vue({
        el: "#app",
        methods: {
            postData() {
                axios.post("http://localhost:8000/", {
                    "username": "m1",
                    "password": 123456
                })
            }
        }
    });
</script>
</body>
</html>

参考

type LoginInfo struct {
	Username string `json:username`
	Password int    `json:password`
}

body, _ := ioutil.ReadAll(r.Body)
var loginInfo LoginInfo
json.Unmarshal(body, &loginInfo)
fmt.Println(loginInfo)
posted @ 2019-11-21 22:35  mmaotai  阅读(194)  评论(0编辑  收藏  举报