跳至主要內容

协程与http请求基本使用

Mr.Lexon大约 3 分钟back-end

协程与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 富心路 31114.296798,22.752729 门牌号}]}
1
广东省深圳市龙岗区富心路31

要点

  1. 创建channel是要添加缓存数量,否则会出现死锁情况
  2. waitgroup要添加任务数量,否则无法阻塞代码导致提前执行
  3. channel使用完之后要及时关闭,否则会出现死循环情况导致程序无法退出(可进行业务需求自定义退出命令)
  4. 当无法确定输入channel的数据类型是可使用interface{}但是在循环中要添加switch代码对导出的数据找对对应的结构体类型,否则循环出来的是interface{}类型从而无法操作

语法糖

for req := range ch1

这里的ch1可以替代成数组,map,channel(类型)已达forEach的功能

switch v := req.(type)

这个v指的是req的数据类型

上次编辑于:
贡献者: Lexon