GoCN每日新闻(2017-06-25)

回复

每日新闻astaxie 发起了问题 • 1 人关注 • 0 个回复 • 20 次浏览 • 2 小时前 • 来自相关话题

beego xsrf 问题

有问必答astaxie 回复了问题 • 2 人关注 • 1 个回复 • 187 次浏览 • 1 天前 • 来自相关话题

GoCN每日新闻(2017-06-24)

回复

每日新闻astaxie 发起了问题 • 1 人关注 • 0 个回复 • 122 次浏览 • 1 天前 • 来自相关话题

请高手帮忙看个golang context的问题

有问必答axlrose 回复了问题 • 5 人关注 • 4 个回复 • 298 次浏览 • 1 天前 • 来自相关话题

grpc客户端需要链接池吗?不是lb内部的对不同的endpoint建立的不同的链接,而是对同样的endpoint需不需要连接池?

有问必答jinleileiking 回复了问题 • 4 人关注 • 3 个回复 • 92 次浏览 • 1 天前 • 来自相关话题

GOLANG如何避免字符串转义

技术讨论winlin 发表了文章 • 0 个评论 • 74 次浏览 • 1 天前 • 来自相关话题

避免转义字符,例如造个json:

json.Unmarshal(`{"code":0, "data":{"server":"127.0.0.1:8080"}}`)查看全部
					

避免转义字符,例如造个json:


json.Unmarshal(`{"code":0, "data":{"server":"127.0.0.1:8080"}}`)

是不是太简单了点,但是我好像并不总是记得。

给大家推荐一款新的编辑神器

文章分享winlin 回复了问题 • 9 人关注 • 8 个回复 • 865 次浏览 • 1 天前 • 来自相关话题

GOLANG宽泛接口在测试中的大用处

技术讨论winlin 发表了文章 • 1 个评论 • 70 次浏览 • 1 天前 • 来自相关话题

考虑测试一个函数:

func request(ctx context.Context, hc *http.Client, api string) (err error... 			查看全部
					

考虑测试一个函数:


func request(ctx context.Context, hc *http.Client, api string) (err error) {
var hreq *http.Request
if hreq, err = http.NewRequest("GET", api, nil); err != nil {
return nil, errors.Wrap(err, "create request")
}
var hres *http.Response
if hres, err = hc.Do(hreq.WithContext(ctx)); err != nil {
return nil, errors.Wrap(err, "do request")
}
defer hres.Body.Close()

var body []byte
if body, err = ioutil.ReadAll(hres.Body); err != nil {
return nil, errors.Wrap(err, "read body")
}

// ......
return nil
}

这个函数的参数是一个*http.Client,而不是接口,这个该如何测试?内嵌一个http.Client像这样吗?


type mockHttpClient struct {
http.Client
}

但是,问题是这样总是很恶心不是吗?就像如果是C++中,我们只能写一个mock类从要测试的类继承,但是我们只需要重写Do这个方法啊。



注意:对于C++而言,这是为何要求构造函数只是初始化,而不能包含逻辑,想象一个类在构造函数就访问了数据库,请问如何MOCK它?是做不到的,因此只能在构造函数初始化数据库的IP和账号等信息,提供connect这种函数连接数据库。


备注:上面只是拿数据库连接打个比方,实际上从MOCK角度来说,构造函数只能初始化内存对象,其他的应该啥也不干。



在GOLANG中,有个非常牛逼的方法,就是创建一个私有的接口,使用时用接口:


type httpDoer interface {
Do(req *http.Request) (*http.Response, error)
}
func request(ctx context.Context, hc httpDoer, api string) (err error) {
// ......

可以发现,很神奇的是,调用者也可以给*http.Client,对这个改动一无所知,这难道不是极其巧妙的设计吗?我们在mock中只需要mock这个方法就可以了。


一行代码处,深藏功与名~

GoCN每日新闻(2017-06-23)

回复

每日新闻astaxie 发起了问题 • 2 人关注 • 0 个回复 • 238 次浏览 • 2 天前 • 来自相关话题

GOLANG测试必须用带堆栈的errors

技术讨论winlin 发表了文章 • 2 个评论 • 143 次浏览 • 2 天前 • 来自相关话题

GOLANG测试时,可以用匿名对象填充测试序列,但是如果没有带堆栈的errors,那么会造成出现错误时无法排查。

GOLANG初始化匿名结构的方式,可以很方便的建立测试集合。

先看测试序列的填充,参考查看全部

GOLANG测试时,可以用匿名对象填充测试序列,但是如果没有带堆栈的errors,那么会造成出现错误时无法排查。


GOLANG初始化匿名结构的方式,可以很方便的建立测试集合。


先看测试序列的填充,参考tricks-2015这个文章,怕你翻不了墙,我把内容粘贴过来就是:


Anonymous structs: test cases (1/2)


These properties enable a nice way to express test cases:


func TestIndex(t *testing.T) {
var tests = []struct {
s string
sep string
out int
}{
{"", "", 0},
{"", "a", -1},
{"fo", "foo", -1},
{"foo", "foo", 0},
{"oofofoofooo", "f", 2},
// etc
}
for _, test := range tests {
actual := strings.Index(test.s, test.sep)
if actual != test.out {
t.Errorf("Index(%q,%q) = %v; want %v", test.s, test.sep, actual, test.out)
}
}
}

是的,看起来很方便,出错时也知道哪里的问题,但是实际上如果序列中有函数,那就悲剧了。让我们来试试,考虑一个包头的定义,它就是两个字段,然后序列化成[]byte


type MyHeader struct {
Version uint8
Size uint16
}

func (v MyHeader) MarshalBinary() ([]byte, error) {
return []byte{byte(v.Version),0,0},nil // Failed.
}

为了测试设置不同的值,得到不同的字节,我们用两个函数来填充测试序列:


func TestMyHeader_MarshalBinary(t *testing.T) {
mhs := []struct {
set func(h *MyHeader)
compare func(p []byte) error
}{
{func(h *MyHeader) { h.Size = 1 }, func(p []byte) error {
if p[1] != 0x01 {
return fmt.Errorf("p[1] is %v", p[1]) // line 194
}
return nil
}},
{func(h *MyHeader) { h.Size = 2 }, func(p []byte) error {
if p[1] != 0x02 {
return fmt.Errorf("p[1] is %v", p[1]) // line 200
}
return nil
}},
}
for _, mh := range mhs {
h := &MyHeader{}
mh.set(h)
if b, err := h.MarshalBinary(); err != nil {
t.Errorf("error is %+v", err)
} else if err = mh.compare(b); err != nil {
t.Errorf("invalid data, err is %+v", err) // line 211
}
}
}

结果我们就懵逼了,出现的错误行数都是在error那个地方211行是不够的,还需要知道是194还是200出问题了:


--- FAIL: TestMyHeader_MarshalBinary (0.00s)
iprouter_test.go:211: invalid data, err is p[1] is 0
iprouter_test.go:211: invalid data, err is p[1] is 0

怎么办呢?把堆栈信息带上,参考错误最佳实践,改成这样:


import oe "github.com/ossrs/go-oryx-lib/errors"

创建error时用这个package:


            if p[1] != 0x01 {
return oe.Errorf("p[1] is %v", p[1]) // line 194
}
if p[1] != 0x02 {
return oe.Errorf("p[1] is %v", p[1]) // line 200
}

结果可以看到详细的堆栈:


    iprouter_test.go:211: invalid data, err is p[1] is 0
_/Users/winlin/git/test/src/core.TestMyHeader_MarshalBinary.func4
/Users/winlin/git/test/src/core_test.go:200
_/Users/winlin/git/test/src/core.TestMyHeader_MarshalBinary
/Users/winlin/git/test/src/core_test.go:210
testing.tRunner
/usr/local/Cellar/go/1.8.1/libexec/src/testing/testing.go:657
runtime.goexit
/usr/local/Cellar/go/1.8.1/libexec/src/runtime/asm_amd64.s:2197

这样可以嵌套非常多的函数做测试了。

重庆 诚聘golang工程师 12k-25k

招聘应聘酒酒 发表了文章 • 2 个评论 • 196 次浏览 • 2 天前 • 来自相关话题

岗位职责:

1.协助架构师完成即时通信系统的技术架构设计与实施; 2.完成服务端通信层和业务层程序的编写。 任职要求:

1.1年golang以上开发经验,熟悉Linux环境及常用命令; 2.熟悉基于TCP/IP、Rpc、Htt... 查看全部

岗位职责:


1.协助架构师完成即时通信系统的技术架构设计与实施;
2.完成服务端通信层和业务层程序的编写。
任职要求:


1.1年golang以上开发经验,熟悉Linux环境及常用命令;
2.熟悉基于TCP/IP、Rpc、Http、Socket等通信编程优先考虑;
3.熟悉C/C++/Java/ python任意一种语言开发经验优先;
4.熟练缓存和nosql数据库使用经验优先考虑;
5.具有一定的架构设计能力优先考虑;
6.有分布式系统开发设计经验,参与开发并成功运维过高并发大据项目的优先考虑;
7.有IM,XMPP,ejabberd开发经验优先。 上班时间:灵活上班时间+双休
地址:重庆市渝北区洪湖西路24号B栋20楼


联系方式:qq:983092900 联系电话:15683298185 或直接将简历发送至983092900@qq.com

GoCN每日新闻(2017-06-22)

回复

每日新闻astaxie 发起了问题 • 1 人关注 • 0 个回复 • 319 次浏览 • 3 天前 • 来自相关话题

golang解析网页,可以做爬虫了

Golang朋也 发表了文章 • 0 个评论 • 310 次浏览 • 3 天前 • 来自相关话题

java里用Jsoup,nodejs里用cheerio,都可以相当方便的解析网页,在golang语言里也找到了一个网页解析的利器,相当的好用,选择器跟jQuery一样

安装

... 查看全部

java里用Jsoup,nodejs里用cheerio,都可以相当方便的解析网页,在golang语言里也找到了一个网页解析的利器,相当的好用,选择器跟jQuery一样



安装


go get github.com/PuerkitoBio/goquery

使用


其实就是项目的readme.md里的demo


package main

import (
"fmt"
"log"

"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
doc, err := goquery.NewDocument("http://metalsucks.net")
if err != nil {
log.Fatal(err)
}

// Find the review items
doc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
// For each item found, get the band and title
band := s.Find("a").Text()
title := s.Find("i").Text()
fmt.Printf("Review %d: %s - %s\n", i, band, title)
})
}

func main() {
ExampleScrape()
}

乱码问题


中文网页都会有乱码问题,因为它默认是utf8编码,这时候就要用到转码器了


安装 iconv-go


go get github.com/djimenez/iconv-go

使用方法


func ExampleScrape() {
res, err := http.Get(baseUrl)
if err != nil {
fmt.Println(err.Error())
} else {
defer res.Body.Close()
utfBody, err := iconv.NewReader(res.Body, "gb2312", "utf-8")
if err != nil {
fmt.Println(err.Error())
} else {
doc, err := goquery.NewDocumentFromReader(utfBody)
// 下面就可以用doc去获取网页里的结构数据了
// 比如
doc.Find("li").Each(func(i int, s *goquery.Selection) {
fmt.Println(i, s.Text())
})
}
}
}

进阶


有些网站会设置Cookie, Referer等验证,可以在http发请求之前设置上请求的头信息


这个不属于goquery里的东西了,想了解更多可以查看golang里的 net/http 包下的方法等信息


baseUrl:="http://baidu.com"
client:=&http.Client{}
req, err := http.NewRequest("GET", baseUrl, nil)
req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")
req.Header.Add("Referer", baseUrl)
req.Header.Add("Cookie", "your cookie") // 也可以通过req.Cookie()的方式来设置cookie
res, err := client.Do(req)
defer res.Body.Close()
//最后直接把res传给goquery就可以来解析网页了
doc, err := goquery.NewDocumentFromResponse(res)

参考



可以愉快的爬人家的网站了




原文:https://tomoya92.github.io/2017/06/21/golang-goquery/

crypto ssh 多个命令怎么一起发?

有问必答chanehua 回复了问题 • 2 人关注 • 1 个回复 • 153 次浏览 • 4 天前 • 来自相关话题

GoCN每日新闻(2017-06-21)

回复

每日新闻astaxie 发起了问题 • 2 人关注 • 0 个回复 • 354 次浏览 • 4 天前 • 来自相关话题