101 lines
1.9 KiB
Go
101 lines
1.9 KiB
Go
// Package http is a http reverse proxy handler
|
|
package http
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
|
|
"github.com/micro/go-micro/api"
|
|
"github.com/micro/go-micro/api/handler"
|
|
"github.com/micro/go-micro/selector"
|
|
)
|
|
|
|
const (
|
|
Handler = "http"
|
|
)
|
|
|
|
type httpHandler struct {
|
|
options handler.Options
|
|
|
|
// set with different initialiser
|
|
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")
|
|
}
|
|
|
|
// create a random selector
|
|
next := selector.Random(service.Services)
|
|
|
|
// get the next node
|
|
s, err := next()
|
|
if err != nil {
|
|
return "", nil
|
|
}
|
|
|
|
return fmt.Sprintf("http://%s:%d", s.Address, s.Port), nil
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|