func (this *Reply) write() { if this.isWebSocket { return } this.writeHeader() if this.redirect { return } if this.data != nil { if reader, ok := this.data.(io.Reader); ok { _, err := io.Copy(this.w, reader) if err != nil { logger.Error("数据输出出现错误:%s", err) return } if limitReader, ok := this.data.(*io.LimitedReader); ok { reader = limitReader.R if closer, ok := reader.(io.Closer); ok { closer.Close() } } if closer, ok := this.data.(io.Closer); ok { closer.Close() } } else { err := this.transport.Out(this.w, this.data) if err != nil { logger.Error("数据序列化失败:%s", err) } } } }
func buildActionHandler(action *defauleAction) (*actionHandler, error) { path := action.GetPath() if !strings.HasPrefix(path, PATH_SEPARATOR) { return nil, errors.New(logger.Error("定义的Uri必须是%s前缀", PATH_SEPARATOR)) } paths := strings.Split(path, PATH_SEPARATOR) uriConversions := make(map[string]int, 0) conversionUri := "" pathSize := 0 for index, p := range paths { pathSize++ if p == "" { continue } if strings.HasPrefix(p, WILDCARD_PREFIX) && strings.HasSuffix(p, WILDCARD_SUFFIX) { name := string([]byte(p)[len(WILDCARD_PREFIX) : len(p)-len(WILDCARD_SUFFIX)]) uriConversions[name] = index p = _conversion } conversionUri += (PATH_SEPARATOR + p) } if conversionUri == "" { conversionUri = PATH_SEPARATOR } exp, err := regexp.Compile(conversionUri) if err != nil { return nil, err } return &actionHandler{exp: exp, method: action.GetMethod(), defineUri: action.GetPath(), hasPathFragments: len(uriConversions) > 0, uriConversions: uriConversions, pathSize: pathSize, service: action.Service}, nil }
func (this *Server) Start() error { logger.Debug("serverConfig is %#v", this.config) this.router.matcher.sort() conf := this.config server := &http.Server{Handler: http.HandlerFunc(this.serverHttpHandler), MaxHeaderBytes: conf.MaxHeaderBytes, TLSConfig: conf.TLSConfig} if conf.ReadTimeout > 0 { server.ReadTimeout = conf.ReadTimeout } if conf.WriteTimeout > 0 { server.WriteTimeout = conf.WriteTimeout } http2.ConfigureServer(server, &http2.Server{}) var err error this.listener, err = net.Listen("tcp", conf.serverAddr) if err != nil { return errors.New(logger.Error("listen [%s] fail:%s", conf.serverAddr, err)) } logger.Info("start HttpServer :%s", conf.serverAddr) keepAliveListrener := tcpKeepAliveListener{this.listener.(*net.TCPListener)} if conf.TLSConfig != nil { conf.TLSConfig.NextProtos = append(conf.TLSConfig.NextProtos, "http/1.1") go server.Serve(tls.NewListener(keepAliveListrener, conf.TLSConfig)) } else { go server.Serve(keepAliveListrener) } return nil }
func (this *pathMatcher) regeditAction(action *defauleAction) error { newActionHandler, err := buildActionHandler(action) if err != nil { logger.Error("添加Action出错:%s", err) return err } actionHandlers, ok := this.actionHandlerMap[action.GetMethod()] if !ok { actionHandlers = make(_actionHandler, 0) } for _, handler := range actionHandlers { if handler.exp.String() == newActionHandler.exp.String() { return errors.New(logger.Error("定义的uri[%s]与[%s]产生冲突,不能添加", handler.defineUri, newActionHandler.defineUri)) } } this.actionHandlerMap[action.GetMethod()] = append(actionHandlers, newActionHandler) return nil }
func newRegexUriPatternMatcher(uriPattern string) uriPatternMatcher { matcher := new(regexUriPatternMatcher) var err error matcher.pattern, err = regexp.Compile(uriPattern) if err != nil { logger.Error("编译正则表达式[%s]异常,%s", uriPattern, err) return nil } return uriPatternMatcher(matcher) }
//创建一个Server,参数可以为空,默认使用0.0.0.0:8888 func NewServer(serverConfig *ServerConfig) *Server { if serverConfig == nil { serverConfig = &ServerConfig{Addr: "0.0.0.0"} } if serverConfig.Port == 0 { serverConfig.Port = 8888 } if serverConfig.OpenHttp2 && serverConfig.TLSConfig == nil { logger.Error("open http2 need TLS support") return nil } addr := net.JoinHostPort(serverConfig.Addr, strconv.Itoa(serverConfig.Port)) serverAddr, err := net.ResolveTCPAddr("tcp", addr) if err != nil { logger.Error("can't parse the server addr [%s],cause:%s", addr, err) return nil } serverConfig.serverAddr = serverAddr.String() return &Server{router: newRoutingDispatcher(), config: serverConfig} }
func (this *actionHandler) doAction(request *http.Request, reply *Reply) { requestUri := request.URL.Path param := make(map[string]string, 0) if this.hasPathFragments { paths := strings.Split(requestUri, PATH_SEPARATOR) if this.pathSize != len(paths) { panic(errors.New(logger.Error("需要解析的uri[%s]不匹配定义的uri[%s]", requestUri, this.defineUri))) } for name, index := range this.uriConversions { param[name] = paths[index] } } this.service(request, param, reply) }
func (route *routingDispatcher) handle(request *http.Request, reply *Reply) { defer func() { if err := recover(); err != nil { reply.SetCode(500).With(err) } }() handler := route.matcher.getActionHandler(request.URL.Path, strings.ToUpper(request.Method)) if handler == nil { reply.SetCode(404).With("404:you are lost") logger.Error("Not found Handler for[%s] [%s]", strings.ToUpper(request.Method), request.URL.Path) return } handler.doAction(request, reply) }
// Index responds with the pprof-formatted profile named by the request. // For example, "/debug/pprof/heap" serves the "heap" profile. // Index responds to a request for "/debug/pprof/" with an HTML page // listing the available profiles. func Index(request *http.Request, pathFragments map[string]string, reply *web.Reply) { if strings.HasPrefix(request.URL.Path, "/debug/pprof/") { name := strings.TrimPrefix(request.URL.Path, "/debug/pprof/") if name != "" { handler(name).RequestHandler(request, pathFragments, reply) return } } r, w := io.Pipe() go func() { defer w.Close() profiles := pprof.Profiles() if err := indexTmpl.Execute(w, profiles); err != nil { logger.Error("出现错误:%s", err) } }() reply.With(r) }
func main() { tlsConfig, err := web.NewTLSConfig("server.crt", "server.key") if err != nil { logger.Error("证书初始化失败,%s", err) time.Sleep(time.Second) return } serConfig := new(web.ServerConfig) serConfig.TLSConfig = tlsConfig serConfig.OpenHttp2 = true server := web.NewServer(serConfig) server.Regedit("/test", web.GET, TestService) server.Regedit("/reqinfo", web.GET, reqInfoHandler) server.Regedit("/a/{name}/123", web.GET, Service) server.AddFilter("/*", web.AccessLogFilter) server.Start() time.Sleep(time.Second * 120) server.Stop() }