How to receive a jsonp request in golang

huangapple go评论114阅读模式
英文:

How to receive a jsonp request in golang

问题

我使用jQuery以jsonp格式发送了一些数据:

console.log(data.location.lng);
console.log(data.location.lat);
console.log(data.accuracy);
var urlgr = "http://127.0.0.1:9220/geo/rec_geo/";
var pfg = {
    //lo: data.location.lng,
    lo: 1.0,
    //la: data.location.lat,
    la: 2.0,
    //ac: data.accuracy,
    ac: 3,
};
$.ajax({
    type: 'GET',
    url: urlgr,
    crossDomain: true,
    data: JSON.stringify(pfg),
    dataType: 'jsonp',
    contentType: "application/json; charset=utf-8",
    success: function (data) {
        console.log("data rec geo");
        console.log(data);

    }
});

这是我用Golang接收它的代码:

type geoData struct {
    Long     float32 `json:"lo"`
    Lat      float32 `json:"la"`
    Accuracy int     `json:"ac"`
}

func recordGeo(w http.ResponseWriter, r *http.Request) {
    s := strings.Split(r.RemoteAddr, ":")
    ip := s[0]
    var geoRec geoData
    decoder := json.NewDecoder(r.Body)
    err := decoder.Decode(&geoRec)
    fmt.Println("geoRec")
    fmt.Println(geoRec)
    checkErr(err)
}

但是我遇到了EOF错误:

2017/07/01 07:16:22 http: panic serving 127.0.0.1:50680: EOF

所以我的问题是如何正确地在Golang中接收一个jsonp请求并将其解析为一个结构体?

这是我在Golang服务器端收到的请求:

GET /geo/rec_geo/?callback=jQuery31108538596418163691_1498913991164&{"lo":1,"la":2,"ac":3}&_=1498913991166 HTTP/1.1
Host: 127.0.0.1:9220
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
accept-encoding: gzip, deflate, sdch, br
accept-language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
referer: http://localhost:8080/
cookie: csrftoken=Y7WA181u22l9sScw9UbPxM38wCGQzjaLMMysAesJSWZm89Pj6CCdBkEF01ibpUjW
alexatoolbar-alx_ns_ph: AlexaToolbar/alx-4.0.1
connection: keep-alive

编辑:删除了Info.Println行,但仍然遇到相同的错误。谢谢。

英文:

I send some data using jquery in the jsonp format :

console.log(data.location.lng);
console.log(data.location.lat);
console.log(data.accuracy);
var urlgr = "http://127.0.0.1:9220/geo/rec_geo/";
var pfg = {
    //lo: data.location.lng,
    lo: 1.0,
    //la: data.location.lat,
    la: 2.0,
    //ac: data.accuracy,
    ac: 3,
};
$.ajax({
    type: 'GET',
    url: urlgr,
    crossDomain: true,
    data: JSON.stringify(pfg),
    dataType: 'jsonp',
    contentType: "application/json; charset=utf-8",
    success: function (data) {
        console.log("data rec geo");
        console.log(data);

    }
});

here is my code in golang to receive it :

type geoData struct {
	Long float32 `json:"lo"`
	Lat   float32  `json:"la"`
	Accuracy  int `json:"ac"`
}

func recordGeo(w http.ResponseWriter, r *http.Request) {
	s := strings.Split(r.RemoteAddr, ":")
	ip := s[0]
	Info.Println("4")
	var geoRec geoData
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&geoRec)
	fmt.Println("geoRec")
	fmt.Println(geoRec)
	checkErr(err)
}

but i have a EOF error :

2017/07/01 07:16:22 http: panic serving 127.0.0.1:50680: EOF

So my question is how to properly receive a jsonp request in golang and parse it to a struct ?

here is the request that i get in the golang server side :

GET /geo/rec_geo/?callback=jQuery31108538596418163691_1498913991164&{%22lo%22:1,%22la%22:2,%22ac%22:3}&_=1498913991166 HTTP/1.1
Host: 127.0.0.1:9220
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
accept-encoding: gzip, deflate, sdch, br
accept-language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
referer: http://localhost:8080/
cookie: csrftoken=Y7WA181u22l9sScw9UbPxM38wCGQzjaLMMysAesJSWZm89Pj6CCdBkEF01ibpUjW
alexatoolbar-alx_ns_ph: AlexaToolbar/alx-4.0.1
connection: keep-alive

edit removed the :
Info.Println line
but i still have the same error

thanks

答案1

得分: 1

JSONP 是用于从服务器接收数据,而不是相反的方式。

你可以阅读更多关于 JSONP 的信息 - 维基百科Stack Overflow 帖子JSONP 示例

实际上,它不仅适用于 Go 语言,你可以在任何服务器端编程中实现 JSONP 处理。


根据你的目的,似乎你需要从 JavaScript/Jquery 发送 JSON Post 请求。然后在 Go 语言的处理程序中执行以下操作:

func recordGeo(w http.ResponseWriter, req *http.Request) {
    decoder := json.NewDecoder(req.Body)
    var geoRec geoData
    if err := decoder.Decode(&geoRec); err != nil {
        fmt.Println(err)
    }
    defer req.Body.Close()
    fmt.Println(geoRec)
}
英文:

JSONP is to receive data from the server not the other way around.

You can read more about JSONP - Wikipedia, SO Post and JSONP examples.

Actually it's not specific to Go language, you can implement JSONP handling in any server-side programing.


For your purpose, it seems you need JSON Post request from JavaScript/Jquery. And on Go lang handler do-

func recordGeo(w http.ResponseWriter, req *http.Request) {
    decoder := json.NewDecoder(req.Body)
    var geoRec geoData
    if err := decoder.Decode(&geoRec); err != nil {
        fmt.Println(err)
    }
    defer req.Body.Close()
    fmt.Println(geoRec)
}

答案2

得分: 1

你的golang代码中存在问题,问题出在以下几行代码:

decoder := json.NewDecoder(r.Body)
Info.Println(r.Body)
err := decoder.Decode(&geoRec)

Info.Printlndecoder.Decode都从请求体中读取数据,而请求体是一个io.Reader。在执行完Info.Println之后,读取器处于EOF状态。从这一点开始,任何进一步的Read操作都会导致EOF错误,这也是你在应用程序中看到的错误。如果你移除(注释掉)Info.Println,你就能够成功将数据解码到结构体中。

编辑:
我忘记并且没有注意到JSONP是一个GET请求。JSON数据被嵌入在查询中。尝试以下方法来提取JSON数据(请根据你的需求进行调整)。

//在recordGeo函数内部
//...

callback := ""
geoRec := geoData{}
queries := r.URL.Query()

//参考http://api.jquery.com/jQuery.ajax/
//关于'jsonp'数据类型的参数。
for key, val := range queries {
	if key == "callback" {
		callback = val[0]
	} else if key == "_" {
		//时间戳
	} else {
		//在键中的JSON数据
		dec := json.NewDecoder(bytes.NewBufferString(key))
		err := dec.Decode(&geoRec)
		if err != nil {
			log.Println(err)
		}
		log.Printf("DATA=%#v", geoRec)
	}
}

//...
//进行一些处理
response := "{YOUR RESPONSE DATA}"
if callback != "" {
    w.Header().Set("Content-Type", "application/javascript")
    response = fmt.Sprintf("%s(%s);", callback, response)
}
w.Write([]byte(response))

如果在客户端将数据设置为data: pfg(不使用JSON.stringify),那么在服务器端,每个参数都可以通过查询参数进行访问:

//
lon := queries.Get("lo")
lat := queries.Get("la")
acc := queries.Get("ac")

或者,如果你将AJAX请求数据设置为data: "mydata=" + JSON.stringify(pfg),那么你可以这样提取数据:

mydata := queries.Get("mydata")
dec := json.NewDecoder(bytes.NewBufferString(mydata))
err := dec.Decode(&geoRec)

处理完之后,你需要向客户端发送一个正确的JSONP响应,即callback(DATA);

英文:

There is a problem in your golang code, the following lines:

decoder := json.NewDecoder(r.Body)
Info.Println(r.Body)
err := decoder.Decode(&geoRec)

Both Info.Println and decoder.Decode read from request body which is an io.Reader. After the execution of Info.Println, the reader is at EOF state. From this point, any further Read will result in EOF error, the error you saw in your application. If you remove (comment out) Info.Println, you will be able to decode the data to the struct.

EDIT:
I forgot and didn't paying attention that JSONP is GET request. The JSON data is embedded in the query. Try the following approach to extract JSON data (please adapt to your need).

//snippet inside recordGeo function
//...

callback := ""
geoRec := geoData{}
queries := r.URL.Query()

//See http://api.jquery.com/jQuery.ajax/
//for 'jsonp' data type parameters.
for key, val := range queries {
	if key == "callback" {
		callback = val[0]
	} else if key == "_" {
		//the Timestamp
	} else {
		//JSON data in the key
		dec := json.NewDecoder(bytes.NewBufferString(key))
		err := dec.Decode(&geoRec)
		if err != nil {
			log.Println(err)
		}
		log.Printf("DATA=%#v", geoRec)
	}
}

//...
//do some processing
response := "{YOUR RESPONSE DATA}"
if callback != "" {
    w.Header().Set("Content-Type", "application/javascript")
    response = fmt.Sprintf("%s(%s);", callback, response)
}
w.Write([]byte(response))

If in the client side you set the data as data: pfg (without JSON.stringify), then in the server side, each parameter will be accessible through query parameter:

//
lon := queries.Get("lo")
lat := queries.Get("la")
acc := queries.Get("ac")

OR, if you set the AJAX request data as data: "mydata=" + JSON.stringify(pfg), then you can extract the data as:

mydata := queries.Get("mydata")
dec := json.NewDecoder(bytes.NewBufferString(mydata))
err := dec.Decode(&geoRec)

After processing, you need to send a proper JSONP response to the client, i.e. callback(DATA);.

答案3

得分: 1

我遇到了同样的问题。然后我找到了echo框架(即github.com/labstack/echo包及其中间件),可以完美处理jsonp请求。这里有一个演示,jsonp的示例

希望这能帮到你。

英文:

I've encountered the same issue. Then I found the echo framework (namely github.com/labstack/echo package and its middleware) which can perfectly handle the jsonp request. Here is the demo, cook for jsonp

Hope this could help.

huangapple
  • 本文由 发表于 2017年7月1日 13:24:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/44857638.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定