Кога ще е първата незадължителна защита на проектите?
Какво означава inlining (a.k.a inline expansion)?
Как се увеличава рамера на стека в Go в момента?
Какво се случва, ако решим да пишем в затворен канал?
Какво ще върне recover()
, ако го извикаме без да сме в състояние на паника?
nil
Какво ще изведе този код:
x := []string{"a","b","c"} for v := range x { fmt.Println(v) }
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() { http.HandleFunc("/world", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) }) go http.ListenAndServe(":8282", nil) 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
интерфейса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("/gcdocs/", http.RedirectHandler("/doc/gc", http.StatusMovedPermanently)) 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 тестовеТемплейт:
<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
Няколко библиотеки, които ще улеснят живота ви по темата