GoLang - HTTP服务搭建服务端与客户端(Server - Client)

前言

         前面已经介绍了如何基于HTTP协议搭建服务端和客户端。但是明显发现Server与Client是彼此独立的,不能产生交互。本文就主要介绍一下如何通过客户端访问api时传入不同的请求参数,服务端响应得到不同的内容。

 

正文

         HTTP常用的请求方式分别为GET请求POST请求。下面分别展开介绍:

       (1)带参数的GET请求示例

///  ===== Server =====
package main

import (
	"encoding/json"
	. "fmt"
	"net/http"
	"time"
)

type NewBaseJsonBean struct {
	Code    int         `json:"code"`
	Data    interface{} `json:"data"`
	Message string      `json:"message"`
}

func Task(w http.ResponseWriter, r *http.Request) {
	Printf(" ------ here is Task ------- \n")
	defer r.Body.Close()

	// 解析请求参数
	// queryParam := r.URL.Query()
	// Println("user is ", queryParam.Get("user")) //get the first value associated with the given key
	// Println("pass is ", queryParam.Get("password"))

	r.ParseForm()
	paramUser, bFound1 := r.Form["user"]
	paramPswd, bFound2 := r.Form["password"]
	if !(bFound1 && bFound2) {
		Println("Query illegal!")
		Fprintf(w, "Error! DO NOT ILLEAGEL ACCESS!")
		return
	}
	Printf("User is %s, password is %s\n", paramUser, paramPswd)

	// 业务处理
	result := NewBaseJsonBean{}
	if "hb" == paramUser[0] && "123456" == paramPswd[0] {
		result.Code = 0
		result.Message = "Login success!"
	} else {
		result.Code = -1
		result.Message = "Login failed! Please check your username or password"
	}

	// 模拟延时
	time.Sleep(time.Second * 1)

	// 响应客户端的请求
	content, _ := json.Marshal(result)
	Fprintf(w, string(content))
}

func main() {
	Println("===== This is http server =====")

	http.HandleFunc("/get", Task)

	err := http.ListenAndServe("127.0.0.1:8090", nil)
	if err != nil {
		Println("ListenAndServe error! err is ", err.Error())
	}
}
/// ===== Client =====
package main

import (
	"fmt"
	. "fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

func main() {
	apiUrl := "http://127.0.0.1:8090/get"

	// set URL param
	data := url.Values{}
	data.Set("user", "hb")
	//data.Add("user", "bobo")
	data.Set("password", "123456")

	uri, err := url.ParseRequestURI(apiUrl)
	if err != nil {
		Println("Parse url failed! err is ", err.Error())
		return
	}

	// URL param encode
	Printf("uri.String is '%s'\n", uri.String())
	uri.RawQuery = data.Encode()
	Printf("uri.param is '%s'\n", uri.RawQuery)
	// param, _ := url.ParseQuery(uri.RawQuery)
	// Println("param is", param)
	// for k, v := range param {
	// 	Println(k, v)
	// }

	// 模拟一个Get提交请求
	resp, err := http.Get(uri.String())
	if err != nil {
		Println("Get failed! err is ", err.Error())
		return
	}

	// 关闭连接
	defer resp.Body.Close()

	// 读取报文中所有内容
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		Println("Read from Body failed!, err is ", err.Error())
		return
	}

	// 输出内容
	fmt.Println(string(content))

	time.Sleep(time.Second * 20)
}

       测试方式1:

              先启动Server.exe,再启动Client.exe。运行结果:

        测试方式2:

              启动Server.exe,通过网页访问url。运行结果:

              (A)访问http://127.0.0.1:8090/get?user=hb&password=123456 (正确的url)

              (B)访问http://127.0.0.1:8090/get?user=hb&password=1234567 (password错误的url)

              (C)访问http://127.0.0.1:8090/get?user=hb&passwordr=123456 (字段错误的url)

 

       (2)带参数的POST请求示例

/// ===== Server =====
package main

import (
	"encoding/json"
	. "fmt"
	"io/ioutil"
	"net/http"
	"time"
)

type NewBaseJsonBean struct {
	Code    int         `json:"code"`
	Data    interface{} `json:"data"`
	Message string      `json:"message"`
}

type LoginInfo struct {
	User     string `json:"user"`
	Password string `json:"password"`
}

func Task(w http.ResponseWriter, r *http.Request) {
	Printf(" ------ here is Task ------- \n")
	defer r.Body.Close()

	// 解析请求参数
	// // 1.请求类型是application/x-www-form-urlencoded时解析form数据
	// r.ParseForm()
	// Println("r.PostForm is ", r.PostForm)
	// // paramUser := r.PostForm.Get("user")//get the first value associated with the given key
	// // paramPswd := r.PostForm.Get("password")
	// paramUser, bFound1 := r.Form["user"]
	// paramPswd, bFound2 := r.Form["password"]
	// if !(bFound1 && bFound2) {
	// 	Println("Query illegal!")
	// 	Fprintf(w, "Error! DO NOT ILLEAGEL ACCESS!")
	// 	return
	// }
	// Printf("User is %s, password is %s\n", paramUser, paramPswd)

	// 业务处理
	// result := NewBaseJsonBean{}
	// if "hb" == paramUser[0] && "123456" == paramPswd[0] {
	// 	result.Code = 0
	// 	result.Message = "Login success!"
	// } else {
	// 	result.Code = -1
	// 	result.Message = "Login failed! Please check your username or password"
	// }

	// 2.请求类型是application/json时从r.Body中读取数据
	param, err := ioutil.ReadAll(r.Body)
	if err != nil {
		Println("Read from Body failed!, err is ", err.Error())
		return
	}
	Println(string(param))
	loginInfo := LoginInfo{}
	err = json.Unmarshal(param, &loginInfo)
	if err != nil {
		Println("Unmarshal failed! err is ", err.Error())
		Fprintf(w, "Error! DO NOT ILLEAGEL ACCESS!")
		return
	}

	// 业务处理
	result := NewBaseJsonBean{}
	if "hb" == loginInfo.User && "123456" == loginInfo.Password {
		result.Code = 0
		result.Message = "Login success!"
	} else {
		result.Code = -1
		result.Message = "Login failed! Please check your username or password"
	}

	// 模拟延时
	time.Sleep(time.Second * 1)

	// 响应客户端的请求
	content, _ := json.Marshal(result)
	Fprintf(w, string(content))
}

func main() {
	Println("===== This is http server =====")

	http.HandleFunc("/post", Task)

	err := http.ListenAndServe("127.0.0.1:8090", nil)
	if err != nil {
		Println("ListenAndServe error! err is ", err.Error())
	}
}
/// ===== Client =====
package main

import (
	"fmt"
	. "fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

func main() {
	apiUrl := "http://127.0.0.1:8090/post"

	// 表单数据
	// contentType := "application/x-www-form-urlencoded"
	// data := "user=hb&password=123456&password=123321"

	contentType := "application/json"
	data := `{"user":"hb","password":"123456"}`

	// 模拟一个Post提交请求
	resp, err := http.Post(apiUrl, contentType, strings.NewReader(data))
	if err != nil {
		Println("Post failed! err is ", err.Error())
		return
	}

	// 关闭连接
	defer resp.Body.Close()

	// 读取报文中所有内容
	content, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		Println("Read from Body failed!, err is ", err.Error())
		return
	}

	// 输出内容
	fmt.Println(string(content))

	time.Sleep(time.Second * 20)
}

       测试:

              先启动Server.exe,再启动Client.exe。运行结果:

 

 

说明

         当请求类型是 application/x-www-form-urlencoded 时,解析表单数据有两种方式,这两种方式是有一定区别的:

      (1)方式一

// 请求类型是application/x-www-form-urlencoded时解析form数据
// 方式一:当传入多个同名key时,所有value都能解析到
r.ParseForm()
Println("r.PostForm is ", r.PostForm)
paramUser, bFound1 := r.Form["user"]
paramPswd, bFound2 := r.Form["password"]
if !(bFound1 && bFound2) {
	Println("Query illegal!")
	Fprintf(w, "Error! DO NOT ILLEAGEL ACCESS!")
	return
}
Printf("User is %s, password is %s\n", paramUser, paramPswd)

// 业务处理
result := NewBaseJsonBean{}
if "hb" == paramUser[0] && "123456" == paramPswd[0] { //由于client端传入的是两个同名password,上边解析时两个password都解析到了数组paramPswd,故这里使用时需要下标取值
	result.Code = 0
	result.Message = "Login success!"
} else {
	result.Code = -1
	result.Message = "Login failed! Please check your username or password"
}

执行结果:

      (2)方式二

// 请求类型是application/x-www-form-urlencoded时解析form数据
// 方式二:当传入多个同名key时,只能解析到第一个value
r.ParseForm()
Println("r.PostForm is ", r.PostForm)
paramUser := r.PostForm.Get("user")
paramPswd := r.PostForm.Get("password")//get the first value associated with the given key
Printf("User is %s, password is %s\n", paramUser, paramPswd)

// 业务处理
result := NewBaseJsonBean{}
if "hb" == paramUser && "123456" == paramPswd {
	result.Code = 0
	result.Message = "Login success!"
} else {
	result.Code = -1
	result.Message = "Login failed! Please check your username or password"
}

执行结果:

 

后言

         好了,到这里为止已经介绍完了通过HTTP服务搭建服务端与客户端的完整流程,快开启你愉快的秃头之旅吧~

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值