返回数据
- 最简单的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!
")
}
h2 := func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello from a HandleFunc #2!
")
}
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)