How to get parameters in POST request - http

I am trying to get the parameters made in a POST request, but I am not able to make it, my code is:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", hello)
fmt.Printf("Starting server for testing HTTP POST...\n")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
func hello(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
switch r.Method {
case "POST":
// Call ParseForm() to parse the raw query and update r.PostForm and r.Form.
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
name := r.Form.Get("name")
age := r.Form.Get("age")
fmt.Print("This have been received:")
fmt.Print("name: ", name)
fmt.Print("age: ", age)
default:
fmt.Fprintf(w, "Sorry, only POST methods are supported.")
}
}
I am making the POST request in the terminal as follows:
curl -X POST -d '{"name":"Alex","age":"50"}' localhost:8080
And then the output is:
This have been received:name: age:
Why it is not taking the parameters? What I am doing wrong?

As you pass your body as a json object, you better define a Go struct matching that object and decode the request body to the object.
type Info struct {
Name string
Age int
}
info := &Info{}
if err := json.NewDecoder(r.Body).Decode(info); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(info)
You can find the whole working code here.
$ curl -X POST -d '{"name":"Alex","age":50}' localhost:8080
This POST request is working fine now.
You could modify the Go struct and also the response object as you like .

Related

Logging All HTTP Request and Response from done through an HTTP Client

I have the following simple http.Client:
import (
"net/http"
"log"
)
...
func main() {
...
link = "http://example.com"
method = "GET"
req, _ := http.NewRequest(method, link, nil)
client := &http.Client{}
myZapLogger.Info("Sending a %s request to %s\n", method, link)
resp, err := client.Do(req)
if err != nil {
myZapLogger.Error(..., err) // I'm logging rather than fatal-ing or so
} else {
myZapLogger.Info("Received a %d on request X", resp.StatusCode)
}
...
}
...
I was looking for a way to do the above for each request through a hook (or so), so that it's triggered automatically each time. I can write a function the encloses all that, but in a case where I'm passing an http client to some other package, I wouldn't be able to control/log such requests that way (e.g. aws-go-sdk).
Is there a way to do this through contexts or attaching hooks to the client?
Thanks
eudore's comment answers the question; I'll just put it into code:
type MyRoundTripper struct {}
func (t MyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// Do work before the request is sent
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
return resp, err
}
// Do work after the response is received
return resp, err
}
To use it, you'll just pass it to your HTTP Client:
rt := MyRoundTripper{}
client := http.Client{Transport: rt}

How to send JSON inside JSON in POST

I am trying to send the following data via a POST HTTP request to an API:
{
"client_interface":{
"source_address":source,
"destination_address":destn,
"message":encrypted_msg,
"business_event_url":settings.Message_CallbackURL
},
"server_interface":{
"message_id":msg_id
}
}
The API is responding with the following error:
{
"Meta":{
"Requestid":12301343169471000
},
"Error":{
"Message":"Request body contains badly-formed JSON (at position 51)",
"Param":""
}
}
CODE:
apiUrl := "http://example.com"
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify : true},
}
jsonStr := []byte(`{
"client_interface": {
"source_address": source,
"destination_address": destn,
"message": encrypted_msg,
"business_event_url": settings.Message_CallbackURL
},
"server_interface": {
"message_id": msg_id
}
}`)
req, err := http.NewRequest("POST", apiUrl, bytes.NewBuffer(jsonStr))
fmt.Println("req..........",req)
if err!=nil{
log.Println("err in http req..............",err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("requestid", msg_id)
req.Header.Set("Authorization", "Bearer "+conn_token)
client := &http.Client{Transport: tr}
resp, err := client.Do(req)
if resp!=nil{
body, _ := ioutil.ReadAll(resp.Body)
}
Using struct :
package main
import (
"fmt"
"net/http"
"io/ioutil"
"bytes"
//"crypto/tls"
"encoding/json"
)
type client_interface struct {
source_address string `json:"string"`
destination_address uint64 `json:"uint64"`
message string `json:"string"`
business_event_url string `json:"string"`
}
type server_interface struct {
message_id uint64 `json:"uint64"`
}
type data struct {
client_interface client_interface `json:"client_interface"`
server_interface server_interface `json:"server_interface"`
}
func main() {
url := "https://example.com"
fmt.Println("URL:>", url)
client_interface := client_interface{}
server_interface := server_interface{}
client_interface.source_address="1"
client_interface.destination_address=1111111111
client_interface.message="khsjhdjks"
client_interface.business_event_url="http://callbackurl-hdfc"
server_interface.message_id=8210993557215399651
fmt.Println("server_interface..........",server_interface)
fmt.Println("client_interface..........",client_interface)
body1 := &data{
client_interface: client_interface,
server_interface: server_interface,
}
fmt.Println("body1..........",body1)
t,e:=json.Marshal(body1)
fmt.Println("t..........",t)
fmt.Println("e..........",e)
req, err := http.NewRequest("POST", url, bytes.NewReader(t))
fmt.Println("req......",req)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("requestid", "8210993557215399651")
req.Header.Set("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyIsImtpZCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyJ9.eyJhdWQiOiJhcGk6Ly90cC1kZXYtdGFubGEtYXBpIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwLyIsImlhdCI6MTU3NTg5MTI3NCwibmJmIjoxNTc1ODkxMjc0LCJleHAiOjE1NzU4OTUxNzQsImFjciI6IjEiLCJhaW8iOiI0MlZnWU9EY3JjenlhZXIxdkRMRDVlNHVtWUxha1UrRUplOVYrZGVlRFgrOTNUMytNRGNBIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjFmMjI1N2ZlLWIzYjktNGQ2Ny05M2YyLWRjNjM2N2Q2MGM4MCIsImFwcGlkYWNyIjoiMCIsImlwYWRkciI6IjE0LjE0My4xODcuMjUwIiwibmFtZSI6ImhkZmMuMTEiLCJvaWQiOiIzOGQxMGFlNS01OGYyLTQ0NjUtYTFkOC04YTc0NDAzYjc5MmEiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiIzNDdUd0ZwYUw5MDhmOXlNRWlGOWNHMU84THFQYmJxZk45VzhyQWVEX1prIiwidGlkIjoiY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwIiwidW5pcXVlX25hbWUiOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1cG4iOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1dGkiOiJuS05TTXRsT3VFeXMtQjRIOGJ3TEFRIiwidmVyIjoiMS4wIn0.F5H9WCOktau3JaqNyWM91A5jFpJ9eJE99fBWvqDq9kOfCk3OCJnHFKXtIaIA7MoqbxWpNZt1yWpVKuw8gd2Lg_9nfUvvXts2DJHVQN0EqQmFUyWTzhdLW8ZVi6E9RtXK2aEWrI2TVceL5C2wbYOQYfvV4LzjTuNbs6k_20cQ0nD6oO1Id16VVFQWy9yKvpDzsTrvlQdFBZeohIfyL9XWKa8DOk0gxe4bjC7OFmuMsF3FZE5XPaQPHOJ3ejlZJiApml2TlRHnvLpkn1biE3NTAu9aO2lE262lyLg8ZaU0sbPuQaS8P797a-outxLvKEMh07895mA9g6vMxEdRV9X2eA")
client := &http.Client{}
resp, err := client.Do(req)
fmt.Println("err.............",err)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("response Status:", resp.Status)
fmt.Println("response Headers:", resp.Header)
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response Body:", string(body))
}
First of all: please use gofmt
Your first code can't work because golang doesn't substitute variables inside string. It's better to use structs.
With structs it's not working because you named struct fields from lower case latter, it means "private" fields in go. So encoding/json package can't access them and just skip them. Use Capital first letters.
Another fix is about 'json:"tag"' - here tag means encoded field name, not type. So instead of 'json:"string"' you should use 'json:"message_id"' or so. You can specify type like this 'json:"field_name,type"' or like this 'json:",type"' but encoding/json guess type on his own.
(I used wrong quotes in tags because of markdown)
I used netcat -l 5000 to listen on 5000 port on localhost and print everything to the terminal. Then I changed url to http://localhost:5000 (not https) to send request to myself.
You need to restart netcat each time to work.
And I made logging a bit more readable.
Also it's CamelCase naming convention in go.
Changed your code a little bit
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"net/http"
//"crypto/tls"
"encoding/json"
"github.com/nikandfor/tlog"
)
type ClientInterface struct {
SourceAddress string `json:"source_address"`
DestinationAddress uint64 `json:"destination_address"`
Message string `json:"message"`
BusinessEventURL string `json:"business_event_url"`
}
type ServerInterface struct {
MessageID uint64 `json:"message_id"`
}
type Data struct {
ClientInterface ClientInterface `json:"client_interface"`
ServerInterface ServerInterface `json:"server_interface"`
}
var (
// use command line flag. so run like so:
// go run ./file.go -addr https://example.com
addr = flag.String("addr", "http://localhost:5000", "address to send data to")
)
func main() {
flag.Parse() // DO NOT FORGET TO PARSE FLAGS
fmt.Println("URL:>", *addr)
clientInterface := ClientInterface{
SourceAddress: "1",
DestinationAddress: 8886121111,
Message: "khsjhdjks",
BusinessEventURL: "http://callbackurl-hdfc",
}
serverInterface := ServerInterface{
MessageID: 8210993557215399651,
}
tlog.Printf("server_interface %+v", serverInterface)
tlog.Printf("client_interface %+v", clientInterface)
body1 := &Data{
ClientInterface: clientInterface,
ServerInterface: serverInterface,
}
tlog.Printf("body %+v", body1)
t, err := json.Marshal(body1)
if err != nil {
panic(err)
}
tlog.Printf("marshalled: %s", t)
req, err := http.NewRequest("POST", *addr, bytes.NewReader(t))
tlog.Printf("req %v", req)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("requestid", "8210993557215399651")
req.Header.Set("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyIsImtpZCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyJ9.eyJhdWQiOiJhcGk6Ly90cC1kZXYtdGFubGEtYXBpIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwLyIsImlhdCI6MTU3NTg5MTI3NCwibmJmIjoxNTc1ODkxMjc0LCJleHAiOjE1NzU4OTUxNzQsImFjciI6IjEiLCJhaW8iOiI0MlZnWU9EY3JjenlhZXIxdkRMRDVlNHVtWUxha1UrRUplOVYrZGVlRFgrOTNUMytNRGNBIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjFmMjI1N2ZlLWIzYjktNGQ2Ny05M2YyLWRjNjM2N2Q2MGM4MCIsImFwcGlkYWNyIjoiMCIsImlwYWRkciI6IjE0LjE0My4xODcuMjUwIiwibmFtZSI6ImhkZmMuMTEiLCJvaWQiOiIzOGQxMGFlNS01OGYyLTQ0NjUtYTFkOC04YTc0NDAzYjc5MmEiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiIzNDdUd0ZwYUw5MDhmOXlNRWlGOWNHMU84THFQYmJxZk45VzhyQWVEX1prIiwidGlkIjoiY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwIiwidW5pcXVlX25hbWUiOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1cG4iOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1dGkiOiJuS05TTXRsT3VFeXMtQjRIOGJ3TEFRIiwidmVyIjoiMS4wIn0.F5H9WCOktau3JaqNyWM91A5jFpJ9eJE99fBWvqDq9kOfCk3OCJnHFKXtIaIA7MoqbxWpNZt1yWpVKuw8gd2Lg_9nfUvvXts2DJHVQN0EqQmFUyWTzhdLW8ZVi6E9RtXK2aEWrI2TVceL5C2wbYOQYfvV4LzjTuNbs6k_20cQ0nD6oO1Id16VVFQWy9yKvpDzsTrvlQdFBZeohIfyL9XWKa8DOk0gxe4bjC7OFmuMsF3FZE5XPaQPHOJ3ejlZJiApml2TlRHnvLpkn1biE3NTAu9aO2lE262lyLg8ZaU0sbPuQaS8P797a-outxLvKEMh07895mA9g6vMxEdRV9X2eA")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
tlog.Printf("response Status: %v", resp.Status)
tlog.Printf("response Headers: %v", resp.Header)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
tlog.Printf("response Body: %s", string(body))
}
$ nc -l 5000
POST / HTTP/1.1
Host: localhost:5000
User-Agent: Go-http-client/1.1
Content-Length: 92
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyIsImtpZCI6IkJCOENlRlZxeWFHckdOdWVoSklpTDRkZmp6dyJ9.eyJhdWQiOiJhcGk6Ly90cC1kZXYtdGFubGEtYXBpIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwLyIsImlhdCI6MTU3NTg5MTI3NCwibmJmIjoxNTc1ODkxMjc0LCJleHAiOjE1NzU4OTUxNzQsImFjciI6IjEiLCJhaW8iOiI0MlZnWU9EY3JjenlhZXIxdkRMRDVlNHVtWUxha1UrRUplOVYrZGVlRFgrOTNUMytNRGNBIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjFmMjI1N2ZlLWIzYjktNGQ2Ny05M2YyLWRjNjM2N2Q2MGM4MCIsImFwcGlkYWNyIjoiMCIsImlwYWRkciI6IjE0LjE0My4xODcuMjUwIiwibmFtZSI6ImhkZmMuMTEiLCJvaWQiOiIzOGQxMGFlNS01OGYyLTQ0NjUtYTFkOC04YTc0NDAzYjc5MmEiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiIzNDdUd0ZwYUw5MDhmOXlNRWlGOWNHMU84THFQYmJxZk45VzhyQWVEX1prIiwidGlkIjoiY2JhYThhYmItZTcwZi00YmI4LWIwNDQtZmZiZjAwNzk0NzkwIiwidW5pcXVlX25hbWUiOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1cG4iOiJoZGZjLjExQFRhbmxhUHJvZHVjdC5vbm1pY3Jvc29mdC5jb20iLCJ1dGkiOiJuS05TTXRsT3VFeXMtQjRIOGJ3TEFRIiwidmVyIjoiMS4wIn0.F5H9WCOktau3JaqNyWM91A5jFpJ9eJE99fBWvqDq9kOfCk3OCJnHFKXtIaIA7MoqbxWpNZt1yWpVKuw8gd2Lg_9nfUvvXts2DJHVQN0EqQmFUyWTzhdLW8ZVi6E9RtXK2aEWrI2TVceL5C2wbYOQYfvV4LzjTuNbs6k_20cQ0nD6oO1Id16VVFQWy9yKvpDzsTrvlQdFBZeohIfyL9XWKa8DOk0gxe4bjC7OFmuMsF3FZE5XPaQPHOJ3ejlZJiApml2TlRHnvLpkn1biE3NTAu9aO2lE262lyLg8ZaU0sbPuQaS8P797a-outxLvKEMh07895mA9g6vMxEdRV9X2eA
Content-Type: application/json
Requestid: 8210993557215399651
Accept-Encoding: gzip
{"client_interface":{"source_address":"1","destination_address":8886121111,"message":"khsjhdjks","business_event_url":"http://callbackurl-hdfc"},"server_interface":{"message_id":8210993557215399651}}
Is it what you've expected?
And the last. I strongly suggest you to read https://golang.org/doc/effective_go.html

golang multiple parseBody for http.request

Hey there I would like to parse a http.resquest two times like below. When I parsed the Body the first time, the body will be closed. I need some help/hint what the best way is to handle this, do I have to create a copy of the request or is there a better way?
func myfunc(w http.ResponseWriter, req *http.Request) {
err := parseBody(req, &type1){
.....
}
err := parseBody(req, &type2){
.....
}
}
Thanks for help
It's true that you can read body only once and it's ok because to parse body more than once you don't have to read it more that one time. Let's consider simple example:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type RequestData1 struct {
Code string `json:"code"`
Status string `json:"status"`
}
type RequestData2 struct {
Status string `json:"status"`
Message string `json:"message"`
}
func main() {
http.HandleFunc("/post", post)
http.ListenAndServe(":8080", nil)
}
If we use this code:
func post(w http.ResponseWriter, r *http.Request) {
body1, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
rd1 := RequestData1{}
err = json.Unmarshal(body1, &rd1)
if err != nil {
panic(err)
}
body2, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
rd2 := RequestData2{}
err = json.Unmarshal(body2, &rd2)
if err != nil {
panic(err) // panic!!!
}
fmt.Printf("rd1: %+v \nrd2: %+v", rd1, rd2)
w.WriteHeader(http.StatusOK)
w.Write([]byte(`Look into console.`))
}
we will have panic: http: panic serving [::1]:54581: unexpected end of JSON input
but with next code:
func post(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
rd1 := RequestData1{}
err = json.Unmarshal(body, &rd1)
if err != nil {
panic(err)
}
rd2 := RequestData2{}
err = json.Unmarshal(body, &rd2)
if err != nil {
panic(err)
}
fmt.Printf("rd1: %+v \nrd2: %+v", rd1, rd2)
w.WriteHeader(http.StatusOK)
w.Write([]byte(`Look into console.`))
}
all works! You can test it by issuing request:
curl -X POST 'http://localhost:8080/post' \
-H 'Content-Type: application/json' -d '{"code":"200", "status": "OK", "message": "200 OK"}'
Result will be:
rd1: {Code:200 Status:OK}
rd2: {Status:OK Message:200 OK}
When you read request.Body, you're reading the stream from the client (e.g. web browser). The client only sends the request once. If you want to parse it multiple times, read the whole thing out into a buffer (e.g. a []byte) and then parse that as many times as you want. Just be mindful of the potential memory use of many concurrent requests with large payloads, as you'll be holding the full payload in memory at least until you're fully done parsing it.

Call golang jsonrpc with curl

I have "hello world" rpc service written in golang. It works fine and go jsonrpc client is working. But I need to send request with curl and this example doesn't work:
curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"id": 1, "method": "Test.Say", "params": [{"greet": "world"}]}' \
http://localhost:1999/_goRPC_
Go accept connection but produce absolutely no result:
curl: (52) Empty reply from server
Here my go code:
package main
import (
"log"
"os"
"time"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
// RPC Api structure
type Test struct {}
// Greet method arguments
type GreetArgs struct {
Name string
}
// Grret message accept object with single param Name
func (test *Test) Greet(args *GreetArgs, result *string) (error) {
*result = "Hello " + args.Name
return nil
}
// Start server with Test instance as a service
func startServer(ch chan<- bool, port string) {
test := new(Test)
server := rpc.NewServer()
server.Register(test)
listener, err := net.Listen("tcp", ":" + port)
if err != nil {
log.Fatal("listen error:", err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
go server.ServeCodec(jsonrpc.NewServerCodec(conn))
ch <- true
}
}
// Start client and call Test.Greet method
func startClient(port string) {
conn, err := net.Dial("tcp", ":" + port)
if err != nil {
panic(err)
}
defer conn.Close()
c := jsonrpc.NewClient(conn)
var reply string
var args = GreetArgs{"world"}
err = c.Call("Test.Greet", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
log.Println("Result: ", reply)
}
func main() {
if len(os.Args) < 2 {
log.Fatal("port not specified")
}
port := os.Args[1]
ch := make(chan bool)
go startServer(ch, port)
time.Sleep(500 * time.Millisecond)
go startClient(port)
// Produce log message each time connection closes
for {
<-ch
log.Println("Closed")
}
}
The jsonrpc package doesn't support json-rpc over HTTP currently. So, you can't call jsonrpc with curl. If you really want to do that, you can make a HTTP handler that adapts the HTTP request/response to a ServerCodec. For example:
package main
import (
"io"
"log"
"net"
"net/http"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
type HttpConn struct {
in io.Reader
out io.Writer
}
func (c *HttpConn) Read(p []byte) (n int, err error) { return c.in.Read(p) }
func (c *HttpConn) Write(d []byte) (n int, err error) { return c.out.Write(d) }
func (c *HttpConn) Close() error { return nil }
// RPC Api structure
type Test struct{}
// Greet method arguments
type GreetArgs struct {
Name string
}
// Grret message accept object with single param Name
func (test *Test) Greet(args *GreetArgs, result *string) error {
*result = "Hello " + args.Name
return nil
}
// Start server with Test instance as a service
func startServer(port string) {
test := new(Test)
server := rpc.NewServer()
server.Register(test)
listener, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatal("listen error:", err)
}
defer listener.Close()
http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/test" {
serverCodec := jsonrpc.NewServerCodec(&HttpConn{in: r.Body, out: w})
w.Header().Set("Content-type", "application/json")
w.WriteHeader(200)
err := server.ServeRequest(serverCodec)
if err != nil {
log.Printf("Error while serving JSON request: %v", err)
http.Error(w, "Error while serving JSON request, details have been logged.", 500)
return
}
}
}))
}
func main() {
if len(os.Args) < 2 {
log.Fatal("port not specified")
}
port := os.Args[1]
startServer(port)
}
Now you can call it with curl -X POST -H "Content-Type: application/json" -d '{"id": 1, "method": "Test.Greet", "params": [{"name":"world"}]}' http://localhost:port/test
Part of the code is from this post
#jfly has a nifty solution.
Another option, if you still wanted to test with something besides the go jsonrpc cient (probably the easiest option), or use #jfly's answer, is you can use telnet to send raw data:
computer:~ User$ telnet 127.0.0.1 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"method":"Test.Greet","params":[{"Name":"world"}],"id":0}
{"id":0,"result":"Hello world","error":null}
{"method":"Test.Greet","params":[{"Name":"world"}],"id":0}
{"id":0,"result":"Hello world","error":null}
{"method":"Test.Greet","params":[{"Name":"world"}],"id":0}
{"id":0,"result":"Hello world","error":null}
The above is the output including payload I typed in and your server's responses.
tcpdump was my friend when I was figuring out the right payload to send.

Passing a query parameter to the Go HTTP request handler using the MUX package

I am trying to pass an additional parameter in the request I am trying to send to the Go server -
websocket.create_connection("ws://<ip>:port/x/y?token="qwerty")
The Go server implementation is as follows -
func main() {
err := config.Parse()
if err != nil {
glog.Error(err)
os.Exit(1)
return
}
flag.Parse()
defer glog.Flush()
router := mux.NewRouter()
http.Handle("/", httpInterceptor(router))
router.Handle("/v1/x", common.ErrorHandler(stats.GetS)).Methods("GET")
router.Handle("/v1/x/y", common.ErrorHandler(stats.GetS)).Methods("GET")
var listen = fmt.Sprintf("%s:%d", config.Config.Ip, config.Config.Port)
err = http.ListenAndServe(listen, nil)
if err != nil {
glog.Error(err)
os.Exit(1)
}
}
func httpInterceptor(router http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
startTime := time.Now()
if !auth.Auth(w, req) {
http.Error(w, "Failed authentication", 401)
return
}
router.ServeHTTP(w, req)
finishTime := time.Now()
elapsedTime := finishTime.Sub(startTime)
switch req.Method {
case "GET":
case "POST":
}
})
}
How should I look and parse for the token in the Go server so that the authentication is successful?
Library function
func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {
// Look for an Authorization header
if ah := req.Header.Get("Authorization"); ah != "" {
// Should be a bearer token
if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
return Parse(ah[7:], keyFunc)
}
}
// Look for "access_token" parameter
req.ParseMultipartForm(10e6)
if tokStr := req.Form.Get("access_token"); tokStr != "" {
return Parse(tokStr, keyFunc)
}
return nil, ErrNoTokenInRequest
}
Call FormValue to get a query parameter:
token := req.FormValue("token")
req is a the *http.Request
An alternative is to call ParseForm and access req.Form directly:
if err := req.ParseForm(); err != nil {
// handle error
}
token := req.Form.Get("token")
The OP asks in a comment how to map "token" to "access_token" for an external package that's looking "access_token". Execute this code before calling the external package:
if err := req.ParseForm(); err != nil {
// handle error
}
req.Form["access_token"] = req.Form["token"]
When the external package calls req.Form.Get("access_token"), it will get the same value as the "token" parameter.
Depending on the way you want to parse the token , if its coming from the form or the URL.
The first answer can be used if the token is being sent from the form while in case of a URL, I would suggest using this. This works for me
token := req.URL.Query().Get("token")
For url query parameters:
mux.Vars(r)["token"]

Resources