在go语言中与PayPal的IPN(即时付款通知)接口的示例

2023-06-01 00:00:00 示例 接口 中与

PayPal已经成为许多创业公司接受在线付款的标准(Stripe最近越来越流行,但他们还没有在全球范围内使用),本教程是关于如何配置你的Golang程序与PayPal的IPN(即时付款通知)接口。

下面是一个如何在Golang中与PayPal的IPN接口的例子:

package main
 import (
 "fmt"
 "io/ioutil"
 "net/http"
 "net/url"
 "regexp"
 "strings"
 )
 // PayPal变量 -- 根据你的要求来改变它。
 // 注意:我决定在这里使用单独的变量,这样我就可以包括
 // 解释。如果把这些变量放到数组中(如url.Values{} ),并在其中加入解释,会更好、更 "干净"。
 // 成数组(如url.Values{} https://golang.org/pkg/net/url/#Values ),然后
 // 循环数组中的名称和值,在下面的表单隐藏字段中。
 var currency_code = "USD"
//支付宝账户接收资金
 var business = "[your email address at PayPal to receive money]"   
//在PayPal顶部的图像 
 var image_url = "https://d1ohg4ss876yi2.cloudfront.net/logo35x35.png" 
// 将socketloop.com:8080改为你的域名。
// 记住:localhost不工作,IPN模拟器只处理80或443端口。
 var cancel_return = "http://[your domain]/paymentcancelreturn"
 var return_url = "http://[your domain]/paymentsuccess" //return是Golang的关键字
 var notify_url = "http://[your domain]/ipn"            // <--- 对IPN的工作很重要!
//只是自定义字段的一个例子,可以是用户名,等等。使用自定义字段
// 用于额外的验证目的,或在数据库中标记PAID状态。
//在数据库中标记PAID状态,等等。
 var custom = "donation"
// 见
// https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/
//了解 rm 和 _xclick 的含义。
 var rm = "2" // rm 2 equal Return method = POST
 var cmd = "_xclick"
 var item_name = "Donation for SocketLoop"
 var quantity = "1"
 var amount = "5" 
//取消注释以切换到真正的PayPal而不是沙盒。
//var paypal_url = "https://www.paypal.com/cgi-bin/webscr"
 var paypal_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
 func Home(w http.ResponseWriter, r *http.Request) {
 html := "<html><body><h1>You will be directed to PayPal now to pay USD " + amount + " to SocketLoop!</h1>"
 html = html + "<form action=' " + paypal_url + "' method='post'>"
 // now add the PayPal variables to be posted
 // a cleaner way to create an array and use for loop
 html = html + "<input type='hidden' name='currency_code' value='" + currency_code + "'>"
 html = html + "<input type='hidden' name='business' value='" + business + "'>"
 html = html + "<input type='hidden' name='image_url' value='" + image_url + "'>"
 html = html + "<input type='hidden' name='cancel_return' value='" + cancel_return + "'>"
 html = html + "<input type='hidden' name='notify_url' value='" + notify_url + "'>"
 html = html + "<input type='hidden' name='return' value='" + return_url + "'>" //use return instead of return_url
 html = html + "<input type='hidden' name='custom' value='" + custom + "'>"
 html = html + "<input type='hidden' name='rm' value='" + rm + "'>"
 html = html + "<input type='hidden' name='cmd' value='" + cmd + "'>"
 html = html + "<input type='hidden' name='item_name' value='" + item_name + "'>"
 html = html + "<input type='hidden' name='quantity' value='" + quantity + "'>"
 html = html + "<input type='hidden' name='amount' value='" + amount + "'>"
 html = html + " <input type='submit' value='Proceed to PayPal'></form></body></html>"
 w.Write([]byte(fmt.Sprintf(html)))
 }
 func PaymentSuccess(w http.ResponseWriter, r *http.Request) {
// 在这里你可能想感谢用户的订单
// 或者其他什么。 这时的订单信息是在POST
// 变量中。 然而,你并不想 "处理 "这个订单,直到你
//从IPN中得到验证。 这时,你会有代码来
// 给管理员发电子邮件,更新数据库中的付款状态,激活一个
//会员资格,等等。
 html := "<html><body><h1>Thank you! Payment accepted!</h1></body></html>"
 w.Write([]byte(fmt.Sprintf(html)))
 }
 func PaymentCancelReturn(w http.ResponseWriter, r *http.Request) {
 html := "<html><body><h1>Oh ok. Payment cancelled!</h1></body></html>"
 w.Write([]byte(fmt.Sprintf(html)))
 }
 func IPN(w http.ResponseWriter, r *http.Request) {
// 付款已收到,IPN已验证。 这是你
// 更新你的数据库以激活或处理该订单,或设置
// 用户的订单细节,给管理员发电子邮件、
//等等。你可以通过IPN数据访问一系列的信息。
//你可以通过r.Form的IPN数据访问一系列的信息://查看paypal的文档,了解哪些信息
// IPN POST变量中的信息。 基本上,所有的POST变量
// Paypal发送的,我们送回去验证的。
// 在本教程中,我们只是打印出所有的IPN数据。
 fmt.Println("IPN received from PayPal")
 err := r.ParseForm() // need this to get PayPal's HTTP POST of IPN data
 if err != nil {
 fmt.Println(err)
 return
 }
 if r.Method == "POST" {
 var postStr string = paypal_url + "&cmd=_notify-validate&"
 for k, v := range r.Form {
 fmt.Println("key :", k)
 fmt.Println("value :", strings.Join(v, ""))
                        // 注意:将IPN数据k,v存储到一个片断中。它对以后的数据库输入很有用。
 postStr = postStr + k + "=" + url.QueryEscape(strings.Join(v, "")) + "&"
 }
// 为了验证来自PayPal的信息,我们必须按照收到的顺序发送
// 准确地按照收到的顺序发回内容,并在其前面加上
//命令_notify-validate
// 然后,PayPal将发送一个单字的信息,要么是VERIFIED、
// 如果信息是有效的,就发送VERIFIED,如果信息是无效的,就发送INVALID。
// 更多信息请见
// https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNIntro/
//将数据传回PayPal
 client := &http.Client{}
 req, err := http.NewRequest("POST", postStr, nil)
 if err != nil {
 fmt.Println(err)
 return
 }
 req.Header.Add("Content-Type: ", "application/x-www-form-urlencoded")
 // fmt.Println(req)
 resp, err := client.Do(req)
 if err != nil {
 fmt.Println(err)
 return
 }
 fmt.Println("Response : ")
 fmt.Println(resp)
 fmt.Println("Status :")
 fmt.Println(resp.Status)
 
 // 将响应转换为字符串
 respStr, _ := ioutil.ReadAll(resp.Body)
 //fmt.Println("Response String : ", string(respStr))
 verified, err := regexp.MatchString("VERIFIED", string(respStr))
 if err != nil {
 fmt.Println(err)
 return
 }
 if verified {
 fmt.Println("IPN verified")
 fmt.Println("TODO : Email receipt, increase credit, etc")
 } else {
 fmt.Println("IPN validation failed!")
 fmt.Println("Do not send the stuff out yet!")
 }
 }
 }
 func main() {
 // http.Handler
 mux := http.NewServeMux()
 mux.HandleFunc("/", Home)
 mux.HandleFunc("/paymentcancelreturn", PaymentCancelReturn) // remember, case sensitive
 mux.HandleFunc("/paymentsuccess", PaymentSuccess)           // remember, case sensitive
 mux.HandleFunc("/ipn", IPN)
 http.ListenAndServe(":8080", mux)
 }

把域名改成你的,然后运行代码。

将你的浏览器指向主要的URL会显示这个页面:

PayPal.png

并在点击按钮后:

PayPal1.png

付款后跟进:

PayPal2.png

最后,在IPN信息被贴回PayPal并被核实后:

PayPal-IPN.png

r.Form包含IPN的有用数据。

使用这些数据进行额外的验证,例如在发布到PayPal之前确保金额是相同的。

电子邮件或用户名(通过自定义字段)是相同的,然后再发布到PayPal。

这些额外的安全步骤是为了确保在发布过程中没有数据改变(欺骗)。


参考资料 :

https://github.com/paypal/ipn-code-samples/blob/master/paypal_ipn.pl
https://github.com/asadovsky/tadue/blob/master/app/paypal.go
https://www.socketloop.com/tutorials/golang-parsing-or-breaking-down-url

相关文章