• [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!
    ")
    	}
    	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)
    
  • 相关阅读:
    JZOJ 5728. 简单计数|| (容斥+动态规划)
    6638. 【GDOI2020.5.16模拟】Seat (队列)
    JZOJ 5750. 青青草原播种计划 (小性质+线段树)
    JZOJ 5753. 完全二叉树 (可持久化线段树维护hash值)
    JS框架-React.js
    flexbox弹性盒子布局
    压缩js和css文件的原理
    JS判断数据类型的方式
    JS数据类型
    ES6新特性
  • 原文地址:https://www.cnblogs.com/iiiiiher/p/11908885.html
Copyright © 2020-2023  润新知