Google app engine Paypal IPN和Golang在GAE上的集成

Google app engine Paypal IPN和Golang在GAE上的集成,google-app-engine,map,paypal,go,Google App Engine,Map,Paypal,Go,我正在编写一个用于处理Paypal IPN消息和响应的侦听器 根据Paypal IPN要求,监听器必须以相同的顺序将从Paypal收到的值发回,并在值列表的前面插入一个新参数“cmd=_notify-validate” 您的侦听器HTTP将完整、未更改的消息发回PayPal。 注意:此消息必须包含与PayPal原始IPN相同的字段,顺序相同,前面都是cmd=\u notify-validate。此外,此消息必须使用与原始消息相同的编码 然而,Go的url.Values变量是在map数据结构中实现

我正在编写一个用于处理Paypal IPN消息和响应的侦听器

根据Paypal IPN要求,监听器必须以相同的顺序将从Paypal收到的值发回,并在值列表的前面插入一个新参数“cmd=_notify-validate”

您的侦听器HTTP将完整、未更改的消息发回PayPal。 注意:此消息必须包含与PayPal原始IPN相同的字段,顺序相同,前面都是cmd=\u notify-validate。此外,此消息必须使用与原始消息相同的编码

然而,Go的url.Values变量是在map数据结构中实现的,在每次迭代时,不能保证值的顺序是相同的

…当使用范围循环在映射上迭代时,不会指定迭代顺序,也不能保证从一次迭代到下一次迭代的顺序相同”

当调用url.Values编码方法时,它将按键排序

Encode将值编码为按键排序的“URL编码”形式(“bar=baz&foo=qux”)

侦听器在GAE上运行,因此我使用“appengine/urlfetch”的PostForm函数,该函数将url.Values作为第二个参数

c := appengine.NewContext(r)
client := urlfetch.Client(c)
resp, err := client.PostForm("https://www.sandbox.paypal.com/cgi-bin/webscr", r.Form)

由于url.Values是一个映射,映射中的值的顺序不能保证是有序的。我如何可能将参数值以从Paypal IPN接收到的相同顺序通过GAE urlfetch服务传递回Paypal?

使用
Post
而不是
PostForm
。您可能可以使用请求的正文:

var buf bytes.Buffer
buf.WriteString("cmd=_notify-validate&")
io.Copy(&buf, r.Body)

client.Post("http://localhost", "application/x-www-form-urlencoded", &buf)

这是可行的,但在io.Copy(&buf,r.Body)行之后,我尝试运行r.ParseForm()。它没有错误,因为我有错误处理程序。但是,我在r.Form中没有得到任何值。似乎io.Copy对r.Body做了什么?我不能在io.Copy(&buf,r.Body)之前运行ParseForm()因为它以某种方式改变了主体。你知道吗?或者我必须按值复制r.body以单独运行io.copy(&buf,r.body)?是的,很抱歉,使用
io.copy
消耗主体将使
ParseForm
无法使用(反之亦然)您可以用
teereder
::替换主体。因此,在调用
client.Post(…,…,tt)之后,我遇到了
http:invalid Read on closed Body
,而不是
io.Copy
,而是
r.Body=io.teereder(r.Body,&buf)
,然后调用:
r.ParseForm()
。调用io.TeeReader()后,如何保持主体打开?(我使用了一个新变量
tt:=io.TeeReader(r.body,&buf)
,因为TeeReader返回的读卡器不实现closer)抱歉,我没有注意到这一点。您必须自己制作支持关闭的
TeeReader
。这其实并不难,因为
TeeReader
的代码很简单:。下面是一个未经测试的示例:。然后您可以使用
r.Body=TeeReadCloser(r.Body,&buf)