2019-06-03 18:44:43 +01:00
|
|
|
// Package http is a http reverse proxy handler
|
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2020-07-01 17:06:59 +01:00
|
|
|
"math/rand"
|
2019-06-03 18:44:43 +01:00
|
|
|
"net/http"
|
|
|
|
"net/http/httputil"
|
|
|
|
"net/url"
|
|
|
|
|
2020-08-19 17:47:17 +03:00
|
|
|
"github.com/unistack-org/micro/v3/api"
|
|
|
|
"github.com/unistack-org/micro/v3/api/handler"
|
|
|
|
"github.com/unistack-org/micro/v3/registry"
|
2019-06-03 18:44:43 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
Handler = "http"
|
|
|
|
)
|
|
|
|
|
|
|
|
type httpHandler struct {
|
|
|
|
options handler.Options
|
|
|
|
|
2020-07-16 23:33:11 +08:00
|
|
|
// set with different initializer
|
2019-06-03 18:44:43 +01:00
|
|
|
s *api.Service
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
service, err := h.getService(r)
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(service) == 0 {
|
|
|
|
w.WriteHeader(404)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
rp, err := url.Parse(service)
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(500)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// getService returns the service for this request from the selector
|
|
|
|
func (h *httpHandler) getService(r *http.Request) (string, error) {
|
|
|
|
var service *api.Service
|
|
|
|
|
|
|
|
if h.s != nil {
|
|
|
|
// we were given the service
|
|
|
|
service = h.s
|
|
|
|
} else if h.options.Router != nil {
|
|
|
|
// try get service from router
|
|
|
|
s, err := h.options.Router.Route(r)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
service = s
|
|
|
|
} else {
|
|
|
|
// we have no way of routing the request
|
|
|
|
return "", errors.New("no route found")
|
|
|
|
}
|
|
|
|
|
2020-08-21 14:53:21 +03:00
|
|
|
if len(service.Services) == 0 {
|
|
|
|
return "", errors.New("no route found")
|
|
|
|
}
|
|
|
|
|
2020-07-01 17:06:59 +01:00
|
|
|
// get the nodes for this service
|
2020-08-21 14:53:21 +03:00
|
|
|
nodes := make([]*registry.Node, 0, len(service.Services))
|
2020-07-01 17:06:59 +01:00
|
|
|
for _, srv := range service.Services {
|
|
|
|
nodes = append(nodes, srv.Nodes...)
|
|
|
|
}
|
2019-06-03 18:44:43 +01:00
|
|
|
|
2020-07-01 17:06:59 +01:00
|
|
|
// select a random node
|
|
|
|
node := nodes[rand.Int()%len(nodes)]
|
2019-06-03 18:44:43 +01:00
|
|
|
|
2020-07-01 17:06:59 +01:00
|
|
|
return fmt.Sprintf("http://%s", node.Address), nil
|
2019-06-03 18:44:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *httpHandler) String() string {
|
|
|
|
return "http"
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewHandler returns a http proxy handler
|
|
|
|
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
|
|
options := handler.NewOptions(opts...)
|
|
|
|
|
|
|
|
return &httpHandler{
|
|
|
|
options: options,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithService creates a handler with a service
|
|
|
|
func WithService(s *api.Service, opts ...handler.Option) handler.Handler {
|
|
|
|
options := handler.NewOptions(opts...)
|
|
|
|
|
|
|
|
return &httpHandler{
|
|
|
|
options: options,
|
|
|
|
s: s,
|
|
|
|
}
|
|
|
|
}
|