前言:
当前我们对“服务器测速源码”大概比较珍视,姐妹们都需要剖析一些“服务器测速源码”的相关文章。那么小编同时在网上网罗了一些关于“服务器测速源码””的相关文章,希望你们能喜欢,我们一起来了解一下吧!httptest是golang官方源码自带的测试包,它可以非常方便获取http请求结构体,http返回值结构体,以及在本地启动一个loopback的server,方便我们做单测。对于go的web应用程序中往往需要与其他系统进行交互, 比如通过http访问其他系统, 此时就需要一种方法用于打桩来模拟Web服务端和客户端,httptest包即Go语言针对Web应用提供的解决方案。
1,获取返回值
rr := httptest.NewRecorder()
我们创建一个 ResponseRecorder (which satisfies http.ResponseWriter)来记录响应,主要利用httptest.NewRecorder()创建一个http.ResponseWriter,模拟了真实服务端的响应,这种响应时通过调用http.DefaultServeMux.ServeHTTP方法触发的。对应源码位于src/net/http/httptest/recorder.go
type ResponseRecorder struct { // Code is the HTTP response code set by WriteHeader. // // Note that if a Handler never calls WriteHeader or Write, // this might end up being 0, rather than the implicit // http.StatusOK. To get the implicit value, use the Result // method. Code int // HeaderMap contains the headers explicitly set by the Handler. // It is an internal detail. // // Deprecated: HeaderMap exists for historical compatibility // and should not be used. To access the headers returned by a handler, // use the Response.Header map as returned by the Result method. HeaderMap http.Header // Body is the buffer to which the Handler's Write calls are sent. // If nil, the Writes are silently discarded. Body *bytes.Buffer // Flushed is whether the Handler called Flush. Flushed bool result *http.Response // cache of Result's return value snapHeader http.Header // snapshot of HeaderMap at first Write wroteHeader bool}
func NewRecorder() *ResponseRecorder { return &ResponseRecorder{ HeaderMap: make(http.Header), Body: new(bytes.Buffer), Code: 200, }}
它对应的方法如下,可以根据实际需求进行调用。
func (rw *ResponseRecorder) Header() http.Header {func (rw *ResponseRecorder) writeHeader(b []byte, str string) {func (rw *ResponseRecorder) Write(buf []byte) (int, error) {func (rw *ResponseRecorder) WriteString(str string) (int, error) {func (rw *ResponseRecorder) WriteHeader(code int) {func (rw *ResponseRecorder) Flush() {func (rw *ResponseRecorder) Result() *http.Response {
2,获取http请求
req := httptest.NewRequest( http.MethodPost, "/health-check", bytes.NewReader(reqBody), )
在测试的时候可以把http.NewRequest替换为httptest.NewRequest。httptest.NewRequest的第三个参数可以用来传递body数据,必须实现io.Reader接口。httptest.NewRequest不会返回error,无需进行err!=nil检查。解析响应时没直接使用ResponseRecorder,而是调用了Result函数。源码位于src/net/http/httptest/httptest.go
func NewRequest(method, target string, body io.Reader) *http.Request { req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n"))) if body != nil { switch v := body.(type) { case *bytes.Buffer: req.ContentLength = int64(v.Len()) case *bytes.Reader: req.ContentLength = int64(v.Len()) case *strings.Reader: req.ContentLength = int64(v.Len()) default: req.ContentLength = -1 } if rc, ok := body.(io.ReadCloser); ok { req.Body = rc } else { req.Body = io.NopCloser(body) } }
3,本地起模拟服务器
httptest.NewServer(http.HandlerFunc(healthHandler))
模拟服务器的创建使用的是httptest.NewServer函数,它接收一个http.Handler处理API请求的接口。代码示例中使用了Hander的适配器模式,http.HandlerFunc是一个函数类型,实现了http.Handler接口,这里是强制类型转换,不是函数的调用,源码位于:src/net/http/httptest/server.go
type Server struct { URL string // base URL of form with no trailing slash Listener net.Listener // EnableHTTP2 controls whether HTTP/2 is enabled // on the server. It must be set between calling // NewUnstartedServer and calling Server.StartTLS. EnableHTTP2 bool // TLS is the optional TLS configuration, populated with a new config // after TLS is started. If set on an unstarted server before StartTLS // is called, existing fields are copied into the new config. TLS *tls.Config // Config may be changed after calling NewUnstartedServer and // before Start or StartTLS. Config *http.Server // certificate is a parsed version of the TLS config certificate, if present. certificate *x509.Certificate // wg counts the number of outstanding HTTP requests on this server. // Close blocks until all requests are finished. wg sync.WaitGroup mu sync.Mutex // guards closed and conns closed bool conns map[net.Conn]http.ConnState // except terminal states // client is configured for use with the server. // Its transport is automatically closed when Close is called. client *http.Client}
默认会监听127.0.0.1:0
func newLocalListener() net.Listener {if serveFlag != "" {l, err := net.Listen("tcp", serveFlag)l, err := net.Listen("tcp", "127.0.0.1:0")if err != nil {if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
func NewServer(handler http.Handler) *Server { ts := NewUnstartedServer(handler) ts.Start() return ts}
func NewUnstartedServer(handler http.Handler) *Server { return &Server{ Listener: newLocalListener(), Config: &http.Server{Handler: handler}, }}
func (s *Server) Start() { s.URL = "; + s.Listener.Addr().String() s.wrap() s.goServe()
func (s *Server) StartTLS() { s.Listener = tls.NewListener(s.Listener, s.TLS) s.URL = "; + s.Listener.Addr().String() s.wrap() s.goServe()
func NewTLSServer(handler http.Handler) *Server { ts := NewUnstartedServer(handler) ts.StartTLS() return ts}
func (s *Server) Close() { for c, st := range s.conns { if st == http.StateIdle || st == http.StateNew { s.closeConn(c) }
func (s *Server) CloseClientConnections() { for c := range s.conns { go s.closeConnChan(c, ch) }
func (s *Server) goServe() { s.wg.Add(1) go func() { defer s.wg.Done() s.Config.Serve(s.Listener) }()}
在协程里对不同http状态进行不同处理
func (s *Server) wrap() { s.Config.ConnState = func(c net.Conn, cs http.ConnState) { switch cs { case http.StateNew: case http.StateActive: case http.StateIdle: case http.StateHijacked, http.StateClosed:
标签: #服务器测速源码