golang 实现 iOS http2 推送 Apns通知
由于要用到viop和远程推送通知 并使用go作为后台语言 就找到了开源的
https://github.com/RobotsAndPencils/buford
作为代码使用,但是 发现 这个开源代码在 生产环境下 无法推送消息 一直提示 :
the Topic header of the request was not specified and was required 这个错误 这个错误 在开发环境和viop的生产环境里面没问题,但是就在 release的生产环境里面报这个错误! 最终发现 问题 是由于代码中的 server类的Push 在使用时 要传入header头,但是在demo中确直接传nil 发现问题后示例代码改成 : 主要是 从证书中解析出来Topic既BundleID然后再传递给Push函数即可。
id,err := service.Push(deviceToken,&headers,b)//主要需要传入 头参数 package main import ( "encoding/json" "fmt" "os" //"net/http" "github.com/RobotsAndPencils/buford/certificate" "github.com/RobotsAndPencils/buford/payload" "github.com/RobotsAndPencils/buford/payload/badge" "github.com/RobotsAndPencils/buford/push" ) // set these variables appropriately const ( filename = "ck.p12" password = "123456" //host = push.Development host = push.Production deviceToken = "5cbf2c60e4907c2c3c168575d05c80a3f4cde2bbb2ff05bbbed8e3a4f25c615f" ) func main() { // load a certificate and use it to connect to the APN service: cert,err := certificate.Load(filename,password) exitOnError(err) topic := "" if err == nil{ fmt.Printf("err is nil ****n"); fmt.Printf("@@@@@@@@@@@@@@@@@@@????????????????????n"); topic = certificate.TopicFromCert(cert); fmt.Printf("topic: %sn",topic); } client,err := push.NewClient(cert) exitOnError(err) service := push.NewService(client,host) // construct a payload to send to the device: p := payload.APS{ Alert: payload.Alert{Body: "Hello HTTP/2"},Badge: badge.New(42),} b,err := json.Marshal(p) fmt.Println("json.Marshal") exitOnError(err) // push the notification: /* headers := Headers{ ID: "uuid",CollapseID: "game1.score.identifier",Expiration: time.Unix(12622780800,0),LowPriority: true,Topic: "bundle-id",} */ /* headers := push.Headers{}; fmt.Printf("Topic is %sn",headers.Topic) //push.ShowInfo(); reqHeader := http.Header{} headers.showInfo() headers.set(reqHeader); */ var headers push.Headers fmt.Printf("topic: %sn",topic); if topic != "" { headers = push.Headers{ Topic: topic,} fmt.Printf("the Topic is *** %sn",headers.Topic) } id,b) //id,nil,b) fmt.Println("service.Push") exitOnError(err) fmt.Println("apns-id:",id) } func exitOnError(err error) { if err != nil { fmt.Println(err) os.Exit(1) } } //service.go 代码不用修改即可 // Package push sends notifications over HTTP/2 to // Apple's Push Notification Service. package push import ( "bytes" "crypto/tls" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" "golang.org/x/net/http2" ) // Apple host locations for configuring Service. const ( Development = "https://api.development.push.apple.com" Development2197 = "https://api.development.push.apple.com:2197" Production = "https://api.push.apple.com" Production2197 = "https://api.push.apple.com:2197" ) const maxPayload = 4096 // 4KB at most // Service is the Apple Push Notification Service that you send notifications to. type Service struct { Host string Client *http.Client } // NewService creates a new service to connect to APN. func NewService(client *http.Client,host string) *Service { return &Service{ Client: client,Host: host,} } // NewClient sets up an HTTP/2 client for a certificate. func NewClient(cert tls.Certificate) (*http.Client,error) { config := &tls.Config{ Certificates: []tls.Certificate{cert},} config.BuildNameToCertificate() transport := &http.Transport{TLSClientConfig: config} if err := http2.ConfigureTransport(transport); err != nil { return nil,err } return &http.Client{Transport: transport},nil } // Push sends a notification and waits for a response. func (s *Service) Push(deviceToken string,headers *Headers,payload []byte) (string,error) { // check payload length before even hitting Apple. if len(payload) > maxPayload { return "",&Error{ Reason: ErrPayloadTooLarge,Status: http.StatusRequestEntityTooLarge,} } urlStr := fmt.Sprintf("%v/3/device/%v",s.Host,deviceToken) fmt.Printf("the urlStr: %sn",urlStr) fmt.Printf("the payload: %sn",payload) fmt.Printf("the headers: %sn",headers) req,err := http.NewRequest("POST",urlStr,bytes.NewReader(payload)) if err != nil { return "",err } req.Header.Set("Content-Type","application/json") //req.Header.Set("apns-topic","com.zzcs.mengliao") headers.set(req.Header) resp,err := s.Client.Do(req) if err != nil { if e,ok := err.(*url.Error); ok { if e,ok := e.Err.(http2.GoAwayError); ok { // parse DebugData as JSON. no status code known (0) return "",parseErrorResponse(strings.NewReader(e.DebugData),0) } } return "",err } defer resp.Body.Close() if resp.StatusCode == http.StatusOK { return resp.Header.Get("apns-id"),nil } return "",parseErrorResponse(resp.Body,resp.StatusCode) } func parseErrorResponse(body io.Reader,statusCode int) error { var response struct { // Reason for failure Reason string `json:"reason"` // Timestamp for 410 StatusGone (ErrUnregistered) Timestamp int64 `json:"timestamp"` } err := json.NewDecoder(body).Decode(&response) if err != nil { return err } es := &Error{ Reason: mapErrorReason(response.Reason),Status: statusCode,} if response.Timestamp != 0 { // the response.Timestamp is Milliseconds,but time.Unix() requires seconds es.Timestamp = time.Unix(response.Timestamp/1000,0).UTC() } return es } 另外参考了下面的文章:但是没有直接指出我所遇到的问题: http://blog.csdn.net/rodgexue/article/details/54290676 在linux环境下执行上面的语句。需要改几个参数, 一、使用最基本的curl命令来发送apns push。从头开始,如果校验你的服务器能不能发送push呢?通过curl测试是否发送成功是最简单的方式。
二、使用go语言的apns的开源程序来发送push 我的go语言的push找的是GitHub上开源的,下载地址如下:https://github.com/RobotsAndPencils/buford 2.然后可以将以.p12结尾的通用版证书放在这个目录下面 3. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |