golang快速入门(四)初尝http请求

zhangxiaohai · · 3657 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

**提示:本系列文章适合有其他语音基础并对Go有持续冲动的读者** ### 一、golang获取HTTP请求 ##### 1.在golang标准库中提供了net包来处理网络连接,通过http.Get创建http请求并返回服务器响应流。再通过ReadAll读取response全部内容。 ```go package main import ( "fmt" "io/ioutil" "net/http" "os" ) func main() { for _, arg := range os.Args[1:] { res, err := http.Get(arg) if err != nil { fmt.Println(err) os.Exit(1) } b, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { fmt.Println(err) os.Exit(1) } fmt.Printf("%s", b) } } ``` 以访问360为例 ![image-20210530131408230](https://markdown-1257692304.cos.ap-nanjing.myqcloud.com/markdown_img/image-20210530131408230.png) 超时会当成错误被捕获 ![image-20210530131617770](https://markdown-1257692304.cos.ap-nanjing.myqcloud.com/markdown_img/image-20210530131617770.png) --- #### 二、练习 1.函数调用`io.Copy(dst, src)`会从src中读取内容,并将读到的结果写入到dst中,使用这个函数替代掉例子中的ioutil.ReadAll来拷贝响应结构体到os.Stdout,避免申请一个缓冲区(例子中的b)来存储。记得处理io.Copy返回结果中的错误。 ```go package main import ( "bufio" "fmt" "io" "net/http" "os" ) func main() { for _, arg := range os.Args[1:] { res, err := http.Get(arg) if err != nil { fmt.Println(err) os.Exit(1) } out, err := os.Create("/tmp/buf_file2.txt") // 初始化一个 io.Writer wt := bufio.NewWriter(out) result, err := io.Copy(wt, res.Body) defer res.Body.Close() if err != nil { fmt.Println(err) os.Exit(1) } fmt.Println(result) wt.Flush() } } ``` 2.如果输入的url参数没有 `http://` 前缀的话,为这个url加上该前缀。你可能会用到`strings.HasPrefix`这个函数。 `strings.Hasprefix(s, prefix)`可以识别字符串的开头,如s字符串以prefix开头则返回true,否则为false,函数原型如下: ```go func HasPrefix(s, prefix string) bool { return len(s) >= len(prefix) && s[0:len(prefix)] == prefix //通过切片处理 } ``` 我们只需对参数做判断即可。 ```go package main import ( "bufio" "fmt" "io" "net/http" "os" "strings" ) func main() { for _, arg := range os.Args[1:] { if strings.HasPrefix(arg, "http://") { fmt.Println(arg) get_txt(arg) } else { arg = "http://" + arg get_txt(arg) fmt.Println(arg) } } } func get_txt(arg string) { res, err := http.Get(arg) if err != nil { fmt.Println(err) os.Exit(1) } out, err := os.Create("/tmp/buf_file2.txt") // 初始化一个 io.Writer wt := bufio.NewWriter(out) result, err := io.Copy(wt, res.Body) defer res.Body.Close() if err != nil { fmt.Println(err) os.Exit(1) } fmt.Println(result) wt.Flush() } ``` 3.h打印出HTTP协议的状态码,可以从`resp.Status`变量得到该状态码。 我们增加一个get_code函数如下,在main将get_txt替换为get_code即可: ```go func get_code(arg string) { res, err := http.Get(arg) if err != nil { fmt.Println(err) os.Exit(1) } status := res.Status fmt.Println("Http Code :", status) } ``` 结果如下: ![image-20210530152453343](https://markdown-1257692304.cos.ap-nanjing.myqcloud.com/markdown_img/image-20210530152453343.png) --- ### 三、初尝golang并发(扩展) 轻松创建高并发应用是go的特点之一,在我们请求多个url时也可以通过`goroutime`(我理解为协程)来创建并发,再通过信道来传递协程中的数据。我们来创建一个同时请求所有url的应用。 新创建一个`new_routine(arg string, ch chan<- string` goroutine,传入命令行参数、行道。该函数中包含`start_time`和`end_time`用于计算此协程运行的时间。 ```go package main import ( "bufio" "fmt" "io" "io/ioutil" "net/http" "os" "strings" "time" ) func get_txt(arg string) { // ... } func get_code(arg string) { // ... } func main() { start := time.Now() //记录开始时间 ch := make(chan string) //创建一个字符信道 for _, arg := range os.Args[1:] { //根据参数开启协程 if strings.HasPrefix(arg, "http://") { go new_routine(arg, ch) } else { arg = "http://" + arg go new_routine(arg, ch) } } //读取信道数据 for range os.Args[1:] { fmt.Println(<-ch) } end := time.Since(start).Seconds() //结束时间 fmt.Printf("time used :%.2fs\n", end) } func new_routine(arg string, ch chan<- string) { start_time := time.Now() res, err := http.Get(arg) if err != nil { ch <- fmt.Sprintf("err:", err) return } size_bytes, err := io.Copy(ioutil.Discard, res.Body) res.Body.Close() if err != nil { ch <- fmt.Sprintf("reading usl:%v", err) return } end_time := time.Since(start_time).Seconds() ch <- fmt.Sprintf("%.2fs %10d %s", end_time, size_bytes, arg) //执行时间、请求大小、url } ``` `Sprintf`将数据输出到字符串或信道对象中。 `ioutil.Discard`是一个临时垃圾回收站,可以将不关注数据输出到此。 执行后结果如下: ![image-20210530165514957](https://markdown-1257692304.cos.ap-nanjing.myqcloud.com/markdown_img/image-20210530165514957.png) --- 文章来源公众号【容器云实践】[golang快速入门(四)初尝http请求](https://mp.weixin.qq.com/s?__biz=MzkzNjEwNTMyNA==&mid=2247483674&idx=1&sn=9ce29c1f24cbe30484ef45ef3952046e&chksm=c2a28519f5d50c0f5c30af57266aa9090f61b2308d2c48cc575378d6e83be5ccd21e6daddff6&token=479702631&lang=zh_CN#rd) 欢迎关注【容器云实践】,每天学点怪东西。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3657 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传