Golang Http request

Configuration request
interaction HTTP requests and responses in answer mode. go request we would have seen, and the second parameter http.Requests handler function. Its structure is:

type Request struct {
    Method string

    URL *url.URL
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
    ProtoMinor int    // 0
    Header Header
    Body io.ReadCloser
    ContentLength int64
    TransferEncoding []string
    Close bool
    Host string
    Form url.Values
    PostForm url.Values
    MultipartForm *multipart.Form
  ....
    ctx context.Context
}

You can see from the request structure, basic information encompasses all http requests. For the request, the main concern about the requested URL, Method, Header, Body of these structures.

URL
HTTP request to the url format scheme: // [userinfo @] host / path [#fragment], go provides a URL structure, used to map the HTTP request URL [query?].

type URL struct {
  Scheme   string
  Opaque   string
  User     *Userinfo
  Host     string
  Path     string
  RawQuery string
  Fragment string
}

URL format is relatively clear, in fact, it should be a better term URI, Uniform Resource Locator. more important is the url query string query. Typically as a parameter of the get request. Some query using the code division & key1 = value1 & key2 = value2 key-value pair, because the url is ASSIC coding code, and therefore the need for query urlencode. go read query by request.URI.RawQuery

func indexHandler(w http.ResponseWriter, r *http.Request) {
    info := fmt.Sprintln("URL", r.URL, "HOST", r.Host, "Method", r.Method, "RequestURL", r.RequestURI, "RawQuery", r.URL.RawQuery)
    fmt.Fprintln(w, info)
}

☁  ~  curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=vanyar&age=27' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
URL /?lang=zh&version=1.1.0 HOST 127.0.0.1:8000 Method POST RequestURL /?lang=zh&version=1.1.0 RawQuery lang=zh&version=1.1.0

header
header also an important part of the HTTP. Request Header structure have the structure, Header is essentially a map (map [string] [] string). The http protocol header of the key-value as a map in FIG:

    Host: example.com
    accept-encoding: gzip, deflate
    Accept-Language: en-us
    fOO: Bar
    foo: two


    Header = map[string][]string{
        "Accept-Encoding": {"gzip, deflate"},
        "Accept-Language": {"en-us"},
        "Foo": {"Bar", "two"},
    }

The header field contains a lot of communication settings, often requests specify Content-Type.

func indexHandler(w http.ResponseWriter, r *http.Request) {
 
    info := fmt.Sprintln(r.Header.Get("Content-Type"))
    fmt.Fprintln(w, info)
}

☁  ~  curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=vanyar&age=27' "http://127.0.0.1:8000?lang=zh&version=1.1.0"

file application / X-WWW-form-urlencoded
Golng printing provides many functions, basically divided into three categories three. That Print Println and Printf.
Print relatively simple, printed to the standard output stream, Println the same except that the multi-print a newline. As Printf format string is printed, the method returns the number of bytes three printing. Sprint, Sprinln Sprintf string and printing is returned, not to the standard output stream. Fprint, and the results Fprintf Fprinln print to put the output interface io.Writer, HTTP in this object is http.ReponseWriter, returns to the print number bytes.

Body
HTTP data communication, transmitted through the main body. go into the package body Body Request, which is a ReadCloser interface. Reader interface methods is an interface, which has a Read (p [] byte) ( n int, err error) method, thus obtaining the requested data can body by reading a byte array.

func indexHandler(w http.ResponseWriter, r *http.Request) {

    info := fmt.Sprintln(r.Header.Get("Content-Type"))
    len := r.ContentLength
    body := make([]byte, len)
    r.Body.Read(body)
    fmt.Fprintln(w, info, string(body))
}

☁  ~  curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=vanyar&age=27' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
application/x-www-form-urlencoded
 name=vanyar&age=27
可见,当请求的content-type为application/x-www-form-urlencoded, body也是和query一样的格式,key-value的键值对。换成json的请求方式则如下:

☁  ~  curl -X POST -H "Content-Type: application/json" -d '{name: "vanyar", age: 27}' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
application/json
 {name: "vanyar", age: 27}
multipart/form-data的格式用来上传图片,请求的body如下:

☁  ~  curl -X POST -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F "name=vanyar" -F "age=27" "http://127.0.0.1:8000?lang=zh&version=1.1.0"
multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW; boundary=------------------------d07972c7800e4c23
 --------------------------d07972c7800e4c23
Content-Disposition: form-data; name="name"

vanyar
--------------------------d07972c7800e4c23
Content-Disposition: form-data; name="age"

27
--------------------------d07972c7800e4c23--

Form
parsing body can read the data requested by the client. And this data is the key to whether or form-data data, are more primitive. Read directly resolved very troublesome. The body usually form data provided. Thus provides a method of processing these go form data.

Form1
Go provides a method for data analysis ParseForm form provided, i.e., content-type of x-www-form-urlencode data.

func indexHandler(w http.ResponseWriter, r *http.Request) {

    contentType := fmt.Sprintln(r.Header.Get("Content-Type"))

    r.ParseForm()
    fromData := fmt.Sprintf("%#v", r.Form)
    fmt.Fprintf(w, contentType, fromData)

}

☁  ~  curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=vanyar&age=27' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
application/x-www-form-urlencoded
%!(EXTRA string=url.Values{"name":[]string{"vanyar"}, "age":[]string{"27"}, "lang":[]string{"zh"}, "version":[]string{"1.1.0"}})%

A method for reading data structures and generally there are several following:

    fmt.Println(r.Form["lang"])
    fmt.Println(r.PostForm["lang"])
    fmt.Println(r.FormValue("lang"))
    fmt.Println(r.PostFormValue("lang"))

R.Form and r.PostForm which must be after calling ParseForm, we will have the data, otherwise it is an empty array.
The call r.FormValue and r.PostFormValue ( "lang") without the need ParseForm will be able to read the data.

Further r.Form and are r.PostForm array structure, for the same name url parameters are present in the body and, r.Form have two values, namely [ "en", "zh"], with the array and the prefix POST method, data can only be read body.

☁  ~  curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d 'name=vanyar&age=27&lang=en' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
application/x-www-form-urlencoded
%!(EXTRA string=url.Values{"version":[]string{"1.1.0"}, "name":[]string{"vanyar"}, "age":[]string{"27"}, "lang":[]string{"en", "zh"}})%

At this point you can see, lang parameter provides not only the url query, post's body also provides, go to the body of a default priority data, both data have, and will not cover.

If you do not want to read the url parameter, or call PostForm value can be read PostFormValue field.

r.PostForm["lang"][0]
r.PostFormValue["lang"]
对于form-data的格式的数据,ParseForm的方法只会解析url中的参数,并不会解析body中的参数。

☁  ~  curl -X POST -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F "name=vanyar" -F "age=27" -F "lang=en" "http://127.0.0.1:8000?lang=zh&version=1.1.0"
multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW; boundary=------------------------5f87d5bfa764488d
%!(EXTRA string=url.Values{"lang":[]string{"zh"}, "version":[]string{"1.1.0"}}
)%

Therefore, when the content-type of form-data request when, ParseFrom you need to change MutilpartFrom, otherwise r.From not read the contents of the body, you can only read the contents of the query string.

MutilpartFrom
ParseMutilpartFrom method entails providing a read data length of the parameter, and then use the same method of reading the form data, MutilpartFrom body only reads data, the data query does not read the url.

func indexHandler(w http.ResponseWriter, r *http.Request) {
    r.ParseMultipartForm(1024)

    fmt.Println(r.Form["lang"])
    fmt.Println(r.PostForm["lang"])
    fmt.Println(r.FormValue("lang"))
    fmt.Println(r.PostFormValue("lang"))
    fmt.Println(r.MultipartForm.Value["lang"])

    fmt.Fprintln(w, r.MultipartForm.Value)
}

Back map [name: [vanyar] age: [27] lang: [en]] can be seen after the request. That r.MultipartForm.Value and no parameters in the url.

In summary, read urlencode encoding, ParseForm only need to read the form-data encoding method requires the use of ParseMultipartForm. If both parameters url, another body, From and FromValue method can be read. The method with Post prefix can only read the data content of the body. Wherein the data obtained MultipartForm r.MultipartForm.Value access.

File upload
form-data format most used way is to upload the pictures of the time. r.MultipartForm.Value is a body of field data post, r.MultipartForm.File contains the picture data:

func indexHandler(w http.ResponseWriter, r *http.Request) {

    r.ParseMultipartForm(1024)
    fileHeader := r.MultipartForm.File["file"][0]
    fmt.Println(fileHeader)
    file, err := fileHeader.Open()
    if err == nil{
        data, err := ioutil.ReadAll(file)
        if err == nil{
            fmt.Println(len(data))
            fmt.Fprintln(w, string(data))
        }
    }
    fmt.Println(err)
}

After issuing a request, you can see images that return. Of course, go to provide better tools function r.FormFile, upload files directly read data. Without the need to use ParseMultipartForm method.

    file, _, err := r.FormFile("file")

    if err == nil{
        data, err := ioutil.ReadAll(file)
        if err == nil{
            fmt.Println(len(data))
            fmt.Fprintln(w, string(data))
        }
    }
    fmt.Println(err)

This only applies to the case file field when no other field, if you still need to read lang parameters, or the need to add ParseMultipartForm call. Read to upload files, the next step is very common io write files to operate.

JSON
is now popular around the end of the separation, the rise of client data submitted by some framework, angular, vue, react, usually accustomed to json format. For json format, body json string is native. That is, go to decrypt the data structure json go of.

type Person struct {
    Name string
    Age int
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    decode := json.NewDecoder(r.Body)
    var p Person
    err := decode.Decode(&p)
    if err != nil{
        log.Fatalln(err)
    }
    info := fmt.Sprintf("%T\n%#v\n", p, p)
    fmt.Fprintln(w, info)
}

☁  ~  curl -X POST -H "Content-Type: application/json"  -d '{"name": "vanyar", "age": 27 }' "http://127.0.0.1:8000?lang=zh&version=1.1.0"
main.Person
main.Person{Name:"vanyar", Age:27}

More details about json, much later discussion. Visit the official website documentation for more information.

Response
requests and responses is http twin brother, not only their similar message format, related processes and structure are similar. go structure is constructed in response ResponseWriter interface.

type ResponseWriter interface {
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(int)
}

Inside the method is very simple, Header method returns a map of the header structure. WriteHeader response status code is returned. Write back to the client data.

We have used fmt.Fprintln method, data is written directly to the response w. You can also call the characters Write method returns.


func indexHandler(w http.ResponseWriter, r *http.Request) {
    str := `<html>
<head><title>Go Web Programming</title></head>
<body><h1>Hello World</h1></body>
</html>`
    w.Write([]byte(str))
}

☁  ~  curl -i http://127.0.0.1:8000/
HTTP/1.1 200 OK
Date: Wed, 07 Dec 2016 09:13:04 GMT
Content-Length: 95
Content-Type: text/html; charset=utf-8

<html>
<head><title>Go Web Programming</title></head>
<body><h1>Hello World</h1></body>
</html>%     
                                                                             ☁  ~
go根据返回的字符,自动修改成了text/html的Content-Type格式。返回数据自定义通常需要修改header相关信息。

func indexHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(501)
    fmt.Fprintln(w, "No such service, try next door")
}


☁  ~  curl -i http://127.0.0.1:8000/
HTTP/1.1 501 Not Implemented
Date: Wed, 07 Dec 2016 09:14:58 GMT
Content-Length: 31
Content-Type: text/plain; charset=utf-8

No such service, try next door

Redirection
redirection feature makes setting the location and http header status code to achieve.

func indexHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Location", "https://google.com")
    w.WriteHeader(302)
}

☁  ~  curl -i http://127.0.0.1:8000/
HTTP/1.1 302 Found
Location: https://google.com
Date: Wed, 07 Dec 2016 09:20:19 GMT
Content-Length: 31
Content-Type: text/plain; charset=utf-8
重定向是常用的功能,因此go也提供了工具方法,http.Redirect(w, r, "https://google.com", http.StatusFound)。

As with the request Header structure, w.Header there are several methods to set the headers

func (h Header) Add(key, value string) {
    textproto.MIMEHeader(h).Add(key, value)
}

func (h Header) Set(key, value string) {
    textproto.MIMEHeader(h).Set(key, value)
}

func (h MIMEHeader) Add(key, value string) {
    key = CanonicalMIMEHeaderKey(key)
    h[key] = append(h[key], value)
}

func (h MIMEHeader) Set(key, value string) {
    h[CanonicalMIMEHeaderKey(key)] = []string{value}
}

Set and Add method can be set headers, for existing key, Add appends an array of values ​​,, set value is a direct replacement for value. That append and assignment difference.

Json
data request may be JSON, in response to the same data may also be json. restful style api json format data is returned. Json string request is decoded, the response is encoded json string, Go provides standard library encoding / json

type Post struct {
    User string
    Threads []string
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    post := &Post{
        User: "vanyar",
        Threads: []string{"first", "second", "third"},
    }
    json, _ := json.Marshal(post)
    w.Write(json)
}

☁  ~  curl -i http://127.0.0.1:8000/
HTTP/1.1 200 OK
Content-Type: application/json
Date: Thu, 08 Dec 2016 06:45:17 GMT
Content-Length: 54

{"User":"vanyar","Threads":["first","second","third"]}%

Of course, more details of the deal json do this later.

Summary
for web applications, processes the request, the response is returned to the basic content. golang well encapsulates the Request and ReponseWriter were to develop. Whether a request or a response, are treated for url, header and body related data. The fundamental contents of the http protocol.

In addition to data processing body, and sometimes also need to process data in the header, a common example is the treatment cookie. This topic will be discussed in the cookie.

Guess you like

Origin www.cnblogs.com/enumx/p/12330526.html