协程与http请求基本使用
大约 3 分钟
协程与http请求基本使用
前提
address
创建responce结构体
type Response struct {
responce.JsonData
Geocodes []struct {
FormattedAddress string `json:"formatted_address"`
Country string `json:"country"`
Province string `json:"province"`
Citycode string `json:"citycode"`
City string `json:"city"`
District string `json:"district"`
Township []any `json:"township"`
Neighborhood struct {
Name []any `json:"name"`
Type []any `json:"type"`
} `json:"neighborhood"`
Building struct {
Name []any `json:"name"`
Type []any `json:"type"`
} `json:"building"`
Adcode string `json:"adcode"`
Street string `json:"street"`
Number string `json:"number"`
Location string `json:"location"`
Level string `json:"level"`
} `json:"geocodes"`
}
首先实现一个http请求:
func (w Address) GetAddress(address string) (res *Response) {
url := fmt.Sprintf("%s?key=%s&address=%s", w.url, contant.Key, address) //组网址
req, err := http.NewRequest("GET", url, nil)//创建请求
if err != nil {
return nil
}
resp, err := http.DefaultClient.Do(req) //执行请求,返回值是一个byte[],所有要使用io建立输入流
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
body, err := io.ReadAll(resp.Body) //建立输入流
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
var reqBody Response //创建返回结构体
err = json.Unmarshal(body, &reqBody) //json反序列化
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
return &reqBody //返回结构体指针
}
总体文件:
package address
import (
"encoding/json"
"fmt" "io" "net/http" "weather/responce" "weather/service/contant")
type Address struct {
url string
}
type Response struct {
responce.JsonData
Geocodes []struct {
FormattedAddress string `json:"formatted_address"`
Country string `json:"country"`
Province string `json:"province"`
Citycode string `json:"citycode"`
City string `json:"city"`
District string `json:"district"`
Township []any `json:"township"`
Neighborhood struct {
Name []any `json:"name"`
Type []any `json:"type"`
} `json:"neighborhood"`
Building struct {
Name []any `json:"name"`
Type []any `json:"type"`
} `json:"building"`
Adcode string `json:"adcode"`
Street string `json:"street"`
Number string `json:"number"`
Location string `json:"location"`
Level string `json:"level"`
} `json:"geocodes"`
}
func New() (w Address) {
return Address{
url: "https://restapi.amap.com/v3/geocode/geo",
}
}
func (w Address) GetAddress(address string) (res *Response) {
url := fmt.Sprintf("%s?key=%s&address=%s", w.url, contant.Key, address)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
var reqBody Response
err = json.Unmarshal(body, &reqBody)
if err != nil {
fmt.Printf("has error: %s", err.Error())
return nil
}
return &reqBody
}
main
先创建业务结构体
addressUitls := address.New()
接着创建一个channel:
ch1 := make(chan interface{}, 10)
然后创建一个waitGroup,并且设定一个任务数量
var wg sync.WaitGroup
wg.Add(1)
创建一个协程任务,将wg导入到协程里面去
go func(wg *sync.WaitGroup) {
fmt.Println("进入协程1")
body := today.GetToday(440300) //调用请求
ch1 <- body //将响应导入channel中
wg.Done() //任务完成
}(&wg)
添加阻塞代码,等待任务完成之后关闭channel
wg.Wait()
close(ch1)
循环输出请求内容:
for req := range ch1 {
fmt.Println(ch1)
switch v := req.(type) {
case *address.Response:
fmt.Println(req)
fmt.Println(v.Status)
fmt.Println(v.Geocodes[0].FormattedAddress)
break
}
}
整体代码:
package main
import (
"fmt"
"sync" "weather/service/address" "weather/service/weatherUitls")
func main() {
today := weatherUitls.New()
addressUitls := address.New()
var wg sync.WaitGroup
ch1 := make(chan interface{}, 10)
fmt.Println("准备执行")
wg.Add(1)
go func(wg *sync.WaitGroup) {
body := addressUitls.GetAddress("广东省深圳市龙岗区富心路31号")
ch1 <- body
wg.Done()
}(&wg)
wg.Wait()
close(ch1)
for req := range ch1 {
fmt.Println(ch1)
switch v := req.(type) {
case *address.Response:
fmt.Println(req)
fmt.Println(v.Status)
fmt.Println(v.Geocodes[0].FormattedAddress)
break
}
}
}
输出
准备执行
进入协程1
0xc00004e0c0
&{{1 1 OK 10000} [{广东省深圳市龙岗区富心路31号 中国 广东省 0755 深圳市 龙岗区 [
] {[] []} {[] []} 440307 富心路 31号 114.296798,22.752729 门牌号}]}
1
广东省深圳市龙岗区富心路31号
要点
- 创建channel是要添加缓存数量,否则会出现死锁情况
- waitgroup要添加任务数量,否则无法阻塞代码导致提前执行
- channel使用完之后要及时关闭,否则会出现死循环情况导致程序无法退出(可进行业务需求自定义退出命令)
- 当无法确定输入channel的数据类型是可使用
interface{}但是在循环中要添加switch代码对导出的数据找对对应的结构体类型,否则循环出来的是interface{}类型从而无法操作
语法糖
for req := range ch1
这里的ch1可以替代成数组,map,channel(类型)已达forEach的功能
switch v := req.(type)
这个v指的是req的数据类型