HTTP Client

package main
 
import (
 "bufio"
 "fmt"
 "net/http"
)
 
func main() {
 resp, err := http.Get("https://siriusuna.top/%E6%8A%98%E8%85%BE%E6%97%A5%E5%BF%97/Golang")
 if err != nil {
  panic(err)
 }
 defer resp.Body.Close()
 
 fmt.Println("Response status:", resp.Status)
 
 scanner := bufio.NewScanner(resp.Body)
 for i := 0; i < 5 && scanner.Scan(); i++ {
  fmt.Println(scanner.Text())
 }
 
 if err := scanner.Err(); err != nil {
  panic(err)
 }
}
/*
Response status: 200 OK
<!DOCTYPE html>
<html lang="zh" dir="ltr"><head><title>文件夹: 折腾日志/Golang | Siriusuna</title><meta charset="utf-8"/><link rel="preconnect" href="https://cdnjs.clo
udflare.com" crossorigin="anonymous"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="og:site_name" content="シリウ
スの砂"/><meta property="og:title" content="文件夹: 折腾日志/Golang | Siriusuna"/><meta property="og:type" content="website"/><meta name="twitter:card"
 content="summary_large_image"/><meta name="twitter:title" content="文件夹: 折腾日志/Golang | Siriusuna"/><meta name="twitter:description" content="无
描述"/><meta property="og:description" content="无描述"/><meta property="og:image:alt" content="无描述"/><meta property="og:image" content="https://sir
iusuna.top/static/og-image.png"/><meta property="og:image:url" content="https://siriusuna.top/static/og-image.png"/><meta name="twitter:image" content=
"https://siriusuna.top/static/og-image.png"/><meta property="og:image:type" content="image/.png"/><meta property="twitter:domain" content="siriusuna.to
p"/><meta property="og:url" content="https://siriusuna.top/折腾日志/Golang/index"/><meta property="twitter:url" content="https://siriusuna.top/折腾日志
/Golang/index"/><link rel="icon" href="../../static/icon.png"/><meta name="description" content="无描述"/><meta name="generator" content="Quartz"/><lin
k rel="preconnect" href="https://cdn.jsdelivr.net"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css"/><script sr
c="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js" async></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lxgw-we
nkai-screen-webfont/1.7.0/style.css" integrity="sha512-A2sVEqmNCGCac7ji4czWLqCVSn28L0U5lSobS173H+gk+QTV6rH0EH0QEnYk5mz3KPRDmEr+GKM1hfdfLrsFpg==" crosso
rigin="anonymous" referrerpolicy="no-referrer"/><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.css" integ
rity="sha512-LaxQmGd9k/pW51CsEy2nLIlbUXCgsyvUEVT5fSguN2b2OBwHjMi2aiUdEEXSMg8Jvy+bCB01as61aNrHnL2DYQ==" crossorigin="anonymous" referrerpolicy="no-refer
rer"/><link rel="stylesheet" href="https://fontsapi.zeoseven.com/442/main/result.css"/><link href="https://fonts.googleapis.com/css2?family=Monsieur+La
+Doulaise&amp;display=swap" rel="stylesheet"/><link href="../../index.css" rel="stylesheet" type="text/css" data-persist="true"/><style>.expand-button 
{
  position: absolute;
  display: flex;
  float: right;
*/

HTTP Server

The core conception in net/http in Go is Handler which is an interface:

type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}

It takes a *Request and then write the response to ResponseWriter.
The response writer is used to fill in the HTTP response. Here our simple response is just "hello\n".

A common way to write a handler is by using the http.HandlerFunc adapter on functions with the appropriate signature.
(That means when we write a function with this signature, it will converse to http.HandlerFunc when it passed in http.HandleFunc(NO ‘S’))

e.g.,

func hello(w http.ResponseWriter, req *http.Request) {
 fmt.Fprintf(w, "hello\n")
}

This handler does something a little more sophisticated
by reading all the HTTP request headers and echoing them into the response body.

func headers(w http.ResponseWriter, req *http.Request) {
 for name, headers := range req.Header {
  for _, h := range headers {
   fmt.Fprintf(w, "%v: %v\n", name, h)
  }
 }
}

We register our handlers on server routes using the http.HandleFunc convenience function.

It sets up the default router in the net/http package and takes a function as an argument.

func main() {
 // Type conversion: From function to an function type `http.HandlerFunc` which implemented `Handler` interface.
 http.HandleFunc("/hello", hello)
 http.HandleFunc("/headers", headers)
 
 
 // Finally, we call the `ListenAndServe` with the port and a handler.
 // `nil` tells it to use the default router we’ve just set up.
 http.ListenAndServe(":8090", nil)
}

In practice, we’d better creating mux explicitly.

mux := http.NewServeMux()
mux.HandleFunc("/hello", hello)
http.ListenAndServe(":8090", mux)

Note that the handler functions are executed concurrently.

Context

A Context carries deadlines, cancellation signals,
and other request-scoped values across API boundaries and goroutines.

package main
 
import (
 "fmt"
 "net/http"
 "time"
)
 
func hello(w http.ResponseWriter, req *http.Request) {
 ctx := req.Context() // Context can be access with `Context` method
 
 fmt.Println("server: hello handler started")
 defer fmt.Println("server: hello handler ended")
 // Wait for a few seconds before sending a reply to the client.
 // While working, keep an eye on the context’s Done() channel for a signal that
 // we should cancel the work and return as soon as possible.
 select {
 case <-time.After(10 * time.Second):
  fmt.Fprintln(w, "Hello")
 case <-ctx.Done():
  err := ctx.Err() // The context’s Err() method returns an error that explains why the Done() channel was closed.
  fmt.Println("server:", err)
  internalError := http.StatusInternalServerError
  http.Error(w, err.Error(), internalError)
 }
}
 
func main() {
 http.HandleFunc("/hello", hello)
 http.ListenAndServe(":8090", nil)
}
/*
$ go run cmd/context/context.go &
$ curl localhost:8090/hello
server: hello handler started
^C
server: context canceled
server: hello handler ended
*/