Какво трябва да направите до 24-ти декември
Какво ще върне recover()
, ако го извикаме без да сме в състояние на паника?
nil
Какво ще изведе този код:
x := []string{"a","b","c"} for v := range x { fmt.Println(v) }
Какво прави go test ./...
?
Какво е example test и как се прави такъв?
Example<нещо-с-главна-буква>
//Output:...
, който се проверява срещи стандартния изход на функциятаnet
conn, err := net.Dial("tcp", "golang.org:80") if err != nil { // handle error } fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") status, err := bufio.NewReader(conn).ReadString('\n')
func Dial(network, address string) (Conn, error)
net.Conn
network
аргумента и връща правилният тип Connnet.Listener
(интерфейс)Accept
net.Conn
за всяка връзка към сървъра виln, err := net.Listen("tcp", ":8080") if err != nil { // handle error } for { conn, err := ln.Accept() if err != nil { // handle error } go handleConnection(conn) }
net/http
package main
import ( "fmt" "net/http" ) func main() { resp, err := http.Get("http://fmi.golang.bg/") if err != nil { fmt.Println(err) return } fmt.Printf("GET fmi golang site said HTTP %d\n", resp.StatusCode) }
http.Request
и http.Client
може да се правят и по-сложни заявкиtype Request struct { // Method specifies the HTTP method (GET, POST, PUT, etc.). Method string // URL specifies either the URI being requested or the URL to access. URL *url.URL // A header maps request lines to their values. Header Header // И доста други полета, за някои от които ще разкажем след малко... }
Get
, Head
, Post
и PostForm
за улеснениеDo(req *Request) (resp *Response, err error)
Чрез атрибутите на http.Client
имате възможност да определите:
Transport
ще се използва (пр. да зададете proxy)Status
, Header
, Body
и др.
Тялото на отговора може да се чете от Body
(io.ReadCloser
):
package main
import (
"fmt"
"html"
"io/ioutil"
"log"
"net/http"
)
func main() { go http.ListenAndServe(":8282", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %s", html.EscapeString(r.URL.Path)) })) res, err := http.Get("http://localhost:8282/world") if err != nil { log.Fatal(err) } contents, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) } fmt.Printf("Server responded with: %s", contents) }
http.Request
се използва и за получаването на клиентски заявкиerr := req.ParseForm() // handle if err != nil sortOrder := req.Form.Get("sortby")
Повече от един начин да одереш котка:
Request.Form
от тип url.Values
Request.PostForm
от тип url.Values
Request.Body
от тип io.ReadCloser
Request.MultipartForm
от тип *multipart.Form
, след извикване на ParseMultipartForm()
type ResponseWriter interface { // Header returns the header map that will be sent by WriteHeader. Header() Header // Write writes the data to the connection as part of an HTTP reply. Write([]byte) (int, error) // WriteHeader sends an HTTP response header with status code. WriteHeader(int) }
io.Writer
интерфейсаТова ни позволява да си използваме неща като:
fmt.Fprintf(rw, "Нещо си")
за да отговаряме на HTTP заявки...
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
http.HandlerFunc
, за който горният интерфейс е имплементиран:type HandlerFunc func(ResponseWriter, *Request)
http.HandleFunc
добавя ново правило в http.DefaultServeMux
http.ServeMux
е проста имплементация, която само match-ва пътя на заявкатаhttp.NotFoundHandler
NotFoundHandler
- връща 404 и съобщениеTimeoutHandler
- приема друг хендлър и лимитира времето за отговорFileServer
- лесен файлов сървърRedirectHandler
StripPrefix
- премахва част от пътя преди да предаде заявка на подаден хендлърServeMux
също е handlerpackage main
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
func main() { mux := http.NewServeMux() mux.Handle("/doc/", http.FileServer(http.Dir("/usr/share/"))) mux.Handle("/google/", http.RedirectHandler("https://www.google.com", http.StatusTemporaryRedirect)) mux.Handle("/proxy/", http.StripPrefix("/proxy/", httputil.NewSingleHostReverseProxy( &url.URL{Scheme: "https", Host: "mirrors.kernel.org", Path: "/"}, ))) mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { if req.URL.Path == "/" { fmt.Fprintf(w, "Welcome to the jungle!") return } http.NotFound(w, req) }) s := &http.Server{Addr: ":8282", Handler: mux, WriteTimeout: 1 * time.Second} log.Printf("Starting server on %s", s.Addr) log.Fatal(s.ListenAndServe()) }
ResponseWriter
е базов интерфейс, но в някои ситуации ви се налага да имате повече контрол:
type CloseNotifier interface { // CloseNotify returns a channel that receives a single value // when the client connection has gone away. CloseNotify() <-chan bool } type Hijacker interface { // Hijack lets the caller take over the connection. // After a call to Hijack(), the HTTP server library // will not do anything else with the connection. Hijack() (net.Conn, *bufio.ReadWriter, error) }
http.RoundTripper
е абстракцията за изпълнение на единична HTTP request-response транзакция:
type RoundTripper interface { RoundTrip(*Request) (*Response, error) }
http.Transport
е имплементация на http.RoundTripper
, която поддръжа HTTP, HTTPS и проксита. По подразбиране в http
пакета имаме:
var DefaultTransport RoundTripper = &Transport{ Proxy: ProxyFromEnvironment, Dial: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).Dial, TLSHandshakeTimeout: 10 * time.Second, }
httputil
и httptest
с благинкиhttptest
има вградени ResponseRecorder
и Server
имплементации за брутално лесни HTTP end-to-end тестовеhttp.Handle("/index.html", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // server push is available if w implements http.Pusher if p, ok := w.(http.Pusher); ok { p.Push("/static/gopher.png", nil} } // load the main page w.Header().Set("Content-Type", "text/html") w.Write([]byte(`<img src="/static/gopher.png" />`)) }))
Темплейт:
<h1>Editing {{.Title}}</h1> <form action="/save/{{.Title}}" method="POST"> <div><textarea name="body" rows="20" cols="80">{{printf "%s" .Body}}</textarea></div> <div><input type="submit" value="Save"></div> </form>
Изполването му:
func editHandler(w http.ResponseWriter, r *http.Request) { p := &Page{ Title: "Hello, world!", Body: "Lorem ipsum dolor sit amet...", } t, _ := template.ParseFiles("edit.html") t.Execute(w, p) }
text/template
import "text/template" ... t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") Hello, <script>alert('you have been pwned')</script>!
html/template
import "html/template" ... t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>") Hello, <script>alert('you have been pwned')</script>!
html/template
се грижи всичко да е правилно escape-натоContext {{.}} After {{.}} O'Reilly: How are <i>you</i>? <a title='{{.}}'> O'Reilly: How are you? <a href="/{{.}}"> O'Reilly: How are %3ci%3eyou%3c/i%3e? <a href="?q={{.}}"> O'Reilly%3a%20How%20are%3ci%3e...%3f <a onx='f("{{.}}")'> O\x27Reilly: How are \x3ci\x3eyou...? <a onx='f({{.}})'> "O\x27Reilly: How are \x3ci\x3eyou...?" <a onx='pattern = /{{.}}/;'> O\x27Reilly: How are \x3ci\x3eyou...\x3f
Няколко библиотеки, които ще улеснят живота ви по темата
golang.org/x/net/context
context
от стандартната библиотека е малко различен