In curl, I can send post data by -d flag like below example
curl -X POST -d'{"accountID":"1"}' localhost:1234/geInfo
How am I supposed to send accountID value in go-wrk command for a post request?
Unless I am mistaken, it is (currently) not supported to pass post parameters.
I figured that from the code of go-wrk by following the -m="POST" parameter which suggests otherwise. (Offering the method "POST" of course does not imply you can also pass parameters)
The parameter is parsed in main.go:19:
method = flag.String("m", "GET", "the http request method")
then passed on to client in single_node.go:16:
go StartClient(
toCall,
*headers,
*method,
*disableKeepAlives,
responseChannel,
wg,
*totalCalls,
)
where it is received in third place in "meth" variable (client.go:14):
func StartClient(url_, heads, meth string, dka bool, responseChan chan *Response, waitGroup *sync.WaitGroup, tc int) {
and then used here (client.go:55):
req, _ := http.NewRequest(meth, url_, nil)
sets := strings.Split(heads, "\n")
//Split incoming header string by \n and build header pairs
for i := range sets {
split := strings.SplitN(sets[i], ":", 2)
if len(split) == 2 {
req.Header.Set(split[0], split[1])
}
}
timer := NewTimer()
for {
timer.Reset()
resp, err := tr.RoundTrip(req)
respObj := &Response{}
(...)
responseChan <- respObj
}
If post parameters would be passable, they would have to be put somewhere into the Request as you can lookup on the golang http package website:
func NewRequest(method, urlStr string, body io.Reader) (*Request, error)
NewRequest returns a new Request given a method, URL, and optional body.
Related
Gin has encapsulated some methods for constructing response, such as methods *Context.JSON(code int, obj interface{}) and *Context.String(code int, format string, values ...interface{}). These methods all call the method *Context.Render(code int, r render.Render).
// Render writes the response headers and calls render.Render to render data.
func (c *Context) Render(code int, r render.Render) {
c.Status(code)
if !bodyAllowedForStatus(code) {
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
return
}
if err := r.Render(c.Writer); err != nil {
panic(err)
}
}
I wonder why the Render method call the method Status which will set the HTTP response code by calling the method ResponseWriter.WriterHeader(statusCode int) firstly.
r.Render(c.Writer) will write Corresponding Content-Type to the response. Apparently it occurs after setting the status code (after calling method WriterHeader). According to the comment on method ResponseWriter.Header(), changing the header map after a call to WriteHeader (or Write) has no effect unless the modified headers are trailers. But setting Content-Type works in Gin.
func writeContentType(w http.ResponseWriter, value []string) {
header := w.Header()
if val := header["Content-Type"]; len(val) == 0 {
header["Content-Type"] = value
}
}
c.Writer is a gin.ResponseWriter (probably the concrete type gin.responseWriter), not an http.ResponseWriter. While it implements the same interface, it doesn't do it in an identical way. Gin's WriteHeader doesn't send the headers immediately; it just stores the code internally in the writer, and WriteHeaderNow calls the "real" WriteHeader from net/http with the stored code.
WriteHeaderNow is called directly by the function you quoted in the case where there's no body; if there is a body, then WriteHeaderNow gets called on the first Write to the body.
Example:
func createOrUpdateInfluencer(c *gin.Context) { }
How to print the data in the request received in my function?
In my case, I am supposed to receive JSON, how to print it without knowing what it looks like?
Just read and print the body is ok:
func createOrUpdateInfluencer(c *gin.Context) {
body, _ := ioutil.ReadAll(c.Request.Body)
println(string(body))
}
Or if you just want to peek it in middleware, you can put it back after read:
func createOrUpdateInfluencer(c *gin.Context) {
body, _ := ioutil.ReadAll(c.Request.Body)
println(string(body))
c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))
}
by using c.Request you can access to your reqeust object, then print/log everyting you must, like the headers:
fmt.Println(g.Request.Header)
fmt.Println(g.Request.Host)
// etc
I'm looking for an efficient way to read HTTP headers from a textfile to be later sent with an HTTP request. Consider the following code (which currently contains basic net/http request functionality):
func MakeRequest(target string, method string) {
client := &http.Client{}
req, _ := http.NewRequest(method, target, nil)
//Headers manually..
req.Header.Add("If-None-Match", `some value`)
response, _ := client.Do(req)
body, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(body))
}
I started by using ioutil.ReadFile like this:
func main() {
data, _ := ioutil.ReadFile("/opt/tests/req.txt")
fmt.Print(string(data))
}
But taking this text, splitting it by some indicator (lets say ":") and then placing the information in req.Header.Add("var1", "var2") per-header seems like an over-kill.
Question: Any better way to send HTTP requests with headers from a text file in go?
net/http has a method ReadRequest which can create a new Request object from a bufio.Reader. Assuming that your file contains a real HTTP request (instead of only the part of the request which consists of lines with key: value) all you need to do is create a new bufio.Reader from the file, i.e. like this (error handling omitted):
rdr,_ := os.Open("req.txt")
req,_ := http.ReadRequest(bufio.NewReader(rdr))
fmt.Printf("%+v\n", req)
If you only want some headers defined, another option is to define the headers in a Json file and apply the following code (file reading not included):
var jsonMap map[string]string
err = json.Unmarshal(jsonBytesFromFile, &jsonMap)
if err != nil {
log.Fatal("unable to parse json: ", err)
}
for k, v := range jsonMap {
log.Printf("setting Header : %s : %s", k, v)
responseWriter.Header().Add(k, v) // you may prefer Set()
}
The json looks like this:
{
"Content-type": "text/plain",
"Cache-Control": "only-if-cached"
}
I have no idea why I always receive an empty string when sending values in POSTMAN
func main(){
rtr := mux.NewRouter()
rtr.HandleFunc("/search", search).Methods("POST")
}
func search(w http.ResponseWriter, r *http.Request) {
name := r.FormValue("name") //returns empty
}
This is the body request in POSTMAN
screenshot for the body request
{
"name": "markus"
}
I tried to change the body request to form data
Screenshot for form data in post request
But it still didn't work.
Does anyone have a solution?
Thanks
What you have there is not a FormValue but a JSON body. If your JSON object is just a simple map of string to string, then you can do something like this:
func search(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body) // check for errors
keyVal := make(map[string]string)
json.Unmarshal(body, &keyVal) // check for errors
name := keyVal["name"]
// do whatever with name
}
Edit
If you need to parse a form value you need to call ParseForm()
func search(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
// handle err
}
name := r.FormValue("name")
}
Just want to share additional information here.
Please check the Content-Type in Header section of Postman if you are facing any problem in sending your request to the server.
Set Content-Type to application/json for sending raw JSON in request.
Set Content-Type to application/x-www-form-urlencoded if you are sending form values in request. Also select x-www-form-urlencoded in postman's Body section
I'm sending POST request:
req, err := http.NewRequest("POST", link, bytes.NewBuffer(jsonStr))
client := &http.Client{Timeout: tm}
resp, err := client.Do(req)
I receive resp.Header in format with type http.Header
I need to something like this:
[
"Server: nginx/1.4.4",
"Date: Wed, 24 Feb 2016 19:09:49 GMT"
]
I don't know how to approach this problem, because I don't know how to deal with http.Header datatype. Could someone help please
resp.Header is of type http.Header. You can see in the documentation that this type is also a map, so you can access it in two different ways:
1) By using http.Header's methods:
serverValue := resp.Header().Get("Server")
dataValue := resp.Header().Get("Date")
If the header exists, you'll get its first value (keep in mind that there might be multiple values for a single header name); otherwise you'll get an empty string.
2) By using map's methods:
serverValue, ok := resp.Header()["Server"]
dataValue, ok := resp.Header()["Date"]
If the header exists, ok will be true (i.e. the header exists) and you'll get a slice of strings containing all the values for that header; otherwise, ok will be false (i.e. the header doesn't exist).
Use whichever method you prefer.
If you need to iterate over all the header values, you can do it with something like:
for name, value := range resp.Header() {
fmt.Printf("%v: %v\n", name, value)
}
You could use a function like this one:
func HeaderToArray(header http.Header) (res []string) {
for name, values := range header {
for _, value := range values {
res = append(res, fmt.Sprintf("%s: %s", name, value))
}
}
return
}
It should return an array like the one you want.
This solutions is for go version go1.13 windows/amd64.
The request object from http.Request contains Header object. We are using net/http package here. You can get values of all headers by name using following method:
import(
"net/http"
)
type RequestHeaders struct {
ContentType string `json: "content-type"`
Authorization string `json: "authorization"`
}
func getHeaders(r *http.Request) RequestHeaders {
contentType := r.Header.Get("Content-Type")
authorization := r.Header.Get("Authorization")
headers := RequestHeaders{
Content-Type: contentType,
Authorization: authorization}
return headers
}
You can see that we are using r.Header.Get("Content-Type") method to get value of the header.
If the header is missing the Get() method will return empty string.
You can retrieve the response header's first value with resp.Header().Get(), which returns "" if the header key has no values.
Hence, in your case
var a [2]string
a[0] = resp.Header().Get("server")
a[1] = resp.Header().Get("date")