zoukankan      html  css  js  c++  java
  • Go的网络编程

    一, HTTP协议客户端实现

    1, 使用http.NewRequest()方法

    首先创建一个client(客户端)对象,其次创建一个request(请求)对象,最后使用client发生request。详情如下:

    package main
    
    import (
       "fmt"
       "net/http"
    )
    
    func main() {
       testHttpNewRequest()
    }
    
    func testHttpNewRequest() {
       // 创建一个客户端
       client := http.Client{}
       // 创建一个请求,请求方式既可以是GET,也可以是POST
       request, err := http.NewRequest("GET", "http://www.baidu.com/", nil)
       CheckErr(err)
       // 客户端发送请求
       cookName := &http.Cookie{Name: "username", Value: "JACK"}
       // 添加cookie
       request.AddCookie(cookName)
       response, err := client.Do(request)
       CheckErr(err)
       // 设置请求头
       request.Header.Set("Accept-Language", "zh-cn")
       defer response.Body.Close()
       // 查看请求头数据
       fmt.Printf("Header:%+v
    ", request.Header)
       fmt.Printf("响应状态码:%v
    ", response.StatusCode)
       // 操作数据
       if response.StatusCode == 200 {
          //data, err := ioutil.ReadAll(response.Body)
          fmt.Println("网络请求成功")
          CheckErr(err)
          //fmt.Println(string(data))
       } else {
          fmt.Println("网络请求失败", response.Status)
       }
    }
    
    // 检查错误
    func CheckErr(err error) {
       defer func() {
          if ins, ok := recover().(error); ok {
             fmt.Println("程序出现异常: ", ins.Error())
          }
       }()
       if err != nil {
          panic(err)
       }
    }
    

    2, 使用client.Get()方法

    这种方法一共两个步骤,先创建一个client(客户端)对象,然后使用client调用Get()方法

    package main
    
    import (
       "fmt"
       "net/http"
    )
    
    func main() {
       testClientGet()
    }
    
    func testClientGet() {
       // 创建客户端
       client := http.Client{}
       // 通过client去请求
       response, err := client.Get("http://www.baidu.com")
       CheckErr(err)
       fmt.Printf("响应状态码:%v
    ", response.StatusCode)
       if response.StatusCode == 200 {
          fmt.Println("网络请求成功")
          defer response.Body.Close()
       }
    }
    
    // 检查错误
    func CheckErr(err error) {
       defer func() {
          if ins, ok := recover().(error); ok {
             fmt.Println("程序出现异常: ", ins.Error())
          }
       }()
       if err != nil {
          panic(err)
       }
    }
    

    3, 使用client.Post()或client.PostForm()方法

    这种方法也是两个步骤,先创建一个client(客户端)对象,然后使用client调用POST或PostForm()方法。其实client的Post()或PostForm()方法,就是对http.NewRequest()封装。

    4, 使用http.Get()方法

    这个方法只有一个步骤,http的Get()方法就是对DefaultClient.Get()封装。

    package main
    
    import (
       "fmt"
       "net/http"
    )
    
    func main() {
       testHttpGet()
    }
    
    func testHttpGet() {
       // 获取服务器的数据
       response, err := http.Get("http://www.baidu.com")
       CheckErr(err)
       fmt.Printf("响应状态码:%v
    ", response.StatusCode)
       if response.StatusCode == 200 {
          defer response.Body.Close()
          fmt.Println("网络请求成功")
          CheckErr(err)
       } else {
          fmt.Println("请求失败", response.Status)
       }
    }
    
    // 检查错误
    func CheckErr(err error) {
       defer func() {
          if ins, ok := recover().(error); ok {
             fmt.Println("程序出现异常: ", ins.Error())
          }
       }()
       if err != nil {
          panic(err)
       }
    }
    

    5, 使用http.Post()或http.PostForm()方法

    http的Post()函数或PostForm就是对DefaultClient.Post()或DefaultClient.PostForm()的封装。这个方法也只有一个 步骤

    package main
    
    import (
       "fmt"
       "net/http"
       "net/url"
       "strings"
    )
    
    func main() {
       testHttpPost()
    }
    
    func testHttpPost() {
       // 构造参数
       data := url.Values{"City": {"上海"}}
       // 参数转化成body
       reader := strings.NewReader(data.Encode())
       // 发起Post请求MIME格式
       response, err := http.Post("http://wwww.weibo.com.cn/", "application/x-www-form-urlencoded", reader)
       CheckErr(err)
       fmt.Printf("响应状态码:%v
    ", response.StatusCode)
       if response.StatusCode == 200 {
          // 操作响应数据
          defer response.Body.Close()
          fmt.Println("请求成功")
          CheckErr(err)
       } else {
          fmt.Println("请求失败", response.Status)
       }
    }
    
    // 检查错误
    func CheckErr(err error) {
       defer func() {
          if ins, ok := recover().(error); ok {
             fmt.Println("程序出现异常: ", ins.Error())
          }
       }()
       if err != nil {
          panic(err)
       }
    }
    

    二, HTTP协议服务端实现

    ① 启动Web服务的几种方式

    1, 使用http.FileServer()方法

    http.FileServer()搭建的服务器只提供静态文件的访问。应为这种web服务只支持静态文件访问,所以称之为静态文件访问。

    http.ListenAndServer()函数用来启动Web服务,绑定并监听http端口。其中第一个参数为监听地址,第二个参数表示提供文件访问服务的HTTP处理器Hander。

    Handler是一个接口,其中只有ServeHTTP(http.ResponseWrite, *http.Request)这一个方法,只有实现了该方法,就自动实现Handler接口,具体声明如下所示

    type Handler interface {
    	ServeHTTP(ResponseWriter, *Request)
    }
    

    http.FileServer()正好可以返回Handler类型,也就是可以提供文件访问服务的HTTP处理器。

    FileServer()的参数是FileSystem接口,可以使用http.Dir()来指定服务端文件所在的路径。如果该路径中存在index.html文件,则会有限显示html文件,否则会显示文件目录。

    package main
    
    import "net/http"
    
    func main()  {
       testFileServer()
    }
    func testFileServer(){
       http.ListenAndServe(":2003", http.FileServer(http.Dir("/Users/jack_zhou/Documents")))
    }
    

    2, 使用http.HandleFunc()方法

    http.HandleFunc()的作用是注册网络访问的路由。因为它采用的是默认路由分发人物方式,所以称为默认的多路由分发服务。

    HandleFunc()的第一个参数是请求路径的匹配模式,第二个参数是一个函数类型,表示这个请求需要处理的事情。

    作为服务器,随时会处理很多的请求,如果没有路由,就需要使用if else 或switch这样的分支语言进行判断,实在太辛苦。Go提供一个ServeMux()方法去分发任务。HandleFunc()其实就是直接将参数交给DefaultServeMux()来进行处理。

    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
       DefaultServeMux.HandleFunc(pattern, handler)
    }
    

    HandleFunc()是一个典型的函数式编程例子,而函数式编也是GO的特色
    HandleFunc()的第二个参数其实就是Handler接口中的ServeHTTP()方法。所以这第二个参数其实就是实现了Handler接口的handler实例。

    通过http.HandleFunc()注册网络路由时,http.ListenAndServer()的第二个参数为nil,这意味着服务端采用默认的http.DefauleServeMux进行分发处理。

    package main
    
    import (
       "fmt"
       "net/http"
    )
    
    func main() {
       // 绑定路径,触发对应方法
       http.HandleFunc("index", indexHandler)
       // 绑定端口
       // 第一个桉树为监听地址,第二个参数为服务端处理程序,通常为nil,这意味着服务端调用http.DefaultServeMux进行处理。
       err := http.ListenAndServe("localhost:3013", nil)
       fmt.Println(err)
    }
    
    func indexHandler(w http.ResponseWriter, r *http.Request) {
       fmt.Println("/index...")
       w.Write([]byte("首页"))
    }
    

    ② 服务端获取客户请求的数据

    1,Get方式传递参数

    • r.ParseForm(),返回error,判断是否解析传参时出错
    • r.Form属性,返回url.Values,他是map[string][]string类型。一般情况下,使用r.FormValue(key)方法更简洁简便
    • r.FormValue(key)方法可以根据客户端传参的key获取对应的值。
    • 其中r表示*http.Request类型,w表示http.ResponseWriter类型。

    2,Post方式传递参数

    Post传参分为两种情况

    • 普通表单请求(直接使用r.PostFormValue(key)方法,可以根据表单的name取到对应的传值。)
    • 文件上传请求(使用r.FormFile(key)方法,根据文件上传控件的name取到上传文件爱你的File和FileHeader对象,然后通过io的copy()操作实现文件上传。)

    3,获取cookies中的值

    Cookie是一个结构体,可以通过http.SetCookie()函数设置Cookie,通过r.Cookie()方法获取cookie

  • 相关阅读:
    node.js 89行爬虫爬取智联招聘信息
    VUE2开发实战——搜索功能
    一个问题一份收获——请求回来的数据应该怎么处理
    JavaScript学习笔记(散)——继承、构造函数super
    讲解版的导航高亮(新手福利)原生JS
    关于node.js和npm,cnpm的安装记录以及gulp自动构建工具的使用
    HTML5中新添加事件
    javascript鸭式辩型法实现接口
    JS原型与原型链终极详解
    Javascript
  • 原文地址:https://www.cnblogs.com/zhoulixiansen/p/12629256.html
Copyright © 2011-2022 走看看