package handler import ( "bytes" "compress/gzip" "crypto/tls" "encoding/json" "errors" "fmt" "io/ioutil" "log" "net/http" "net/url" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/spf13/cast" "github.com/vulcand/oxy/forward" "github.com/vulcand/oxy/testutils" "gitlab.wodcloud.com/apaas-v3/apaas-meshproxy/src/model" "gitlab.wodcloud.com/apaas-v3/apaas-meshproxy/src/service" ) //var Resp *http.Response func Proxy(c *gin.Context) { appT := time.Now() fmt.Println(`开始:`, appT) applyId := c.Param("applyId") if applyId == "" { res := model.WebRes{} res.Data = "applyId不能为空" c.JSON(200, res) return } apiId := c.Param("apiid") //获取服务相关信息 proxyData, err := service.GetRealPath(applyId, apiId) if err != nil { fmt.Println("err......", err.Error()) c.Error(err) return } // 请求授权方式(0注册的服务无鉴权 1注册的服务通过静态token鉴权 2注册的服务通过动态token鉴权) if proxyData.ReqAuthMthod == 2 { var apaasToken string apaasToken = c.Query("apaasToken") if apaasToken == "" { apaasToken = c.GetHeader("Authorization") } if strings.HasPrefix(apaasToken, "Bearer ") { apaasToken = strings.TrimPrefix(apaasToken, "Bearer ") } fmt.Println("apaasToken:", apaasToken) if apaasToken == "" { c.JSON(403, "请输入token值") return } if proxyData.ApaasToken != apaasToken { c.JSON(403, "输入的token值错误") return } } //proxyData.ReqUrl = "https://apaas3.wodcloud.com/iam/login/#/login" if proxyData.SecondLevel != 1 { res := model.WebRes{} res.ErrMsg = `服务申请未通过审批,请联系组织管理员或超管审批` c.JSON(200, res) return } nowTime := time.Now().Format("2006-01-02") if proxyData.RequestStartTime > nowTime { res := model.WebRes{} res.ErrMsg = `申请使用期限未开始` c.JSON(200, res) return } if proxyData.RequestEndTime < nowTime { res := model.WebRes{} res.ErrMsg = `申请使用期限已过期` c.JSON(200, res) return } /*if proxyData.ServiceEndTime.Before(appT) { res := model.WebRes{} res.ErrMsg = `申请的服务已过期` c.JSON(200, res) return }*/ /*//判断是否超过调用次数是否可以调用 callflag, _, err := service.QueryCallsCount(proxyData) if err != nil { fmt.Println("err......", err.Error(), "无法处理调用次数判断") res := model.WebRes{} res.ErrMsg = `无法处理您的请求` c.JSON(200, res) return } if callflag { res := model.WebRes{} res.ErrMsg = `已达到最大调用量` c.JSON(200, res) return }*/ switch proxyData.ReqAuthMthod { case 0: // 注册的服务无鉴权 c.Request.Header.Del("Authorization") case 1: // 注册的服务通过静态token鉴权 c.Request.Header.Set(proxyData.ReqAuthTokenName, proxyData.ReqAuthToken) case 2: // 注册的服务通过动态token鉴权 // 透传apaasToken break } fmt.Println("判断是否为静态文件") //如果是静态文件 if CheckStaticFile(c.Request.URL.Path) { host := getHost(proxyData.ReqUrl) //var prefix string //if apiId == "" { // prefix= fmt.Sprintf("%s/%s/service/%s/%s/", config.Prefix, config.MeshId,applyId,apiId) //}else { // prefix= fmt.Sprintf("%s/%s/service/%s/", config.Prefix, config.MeshId,applyId) //} // //staticPath:= strings.ReplaceAll(c.Request.URL.Path,prefix,"") fwd, _ := forward.New(forward.PassHostHeader(false)) c.Request.URL = testutils.ParseURI(fmt.Sprintf("%s%s", host, c.Request.URL.Path)) c.Request.RequestURI = getRequestURI(c.Request) c.Request.Host = host fwd.ServeHTTP(c.Writer, c.Request) } else { fmt.Println("开始代理") roundTripper := http.DefaultTransport.(*http.Transport) //roundTripper.ForceAttemptHTTP2 = false roundTripper.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} forwarder, err := forward.New(forward.PassHostHeader(false), forward.RoundTripper(roundTripper), forward.ResponseModifier(func(resp *http.Response) error { respbody, err1 := ioutil.ReadAll(resp.Body) if err1 != nil { log.Println(err1) return errors.New(`数据读取失败`) } var bytesNewBody []byte //是否需要过滤字段 if proxyData.DataServiceType1 == 5 && proxyData.ResFields != "" && proxyData.ResFields != "[]" { //读取数据 bytesNewBody = service.FiledFilter(proxyData, respbody) } else { bytesNewBody = respbody } //放回 resp.Body = ioutil.NopCloser(bytes.NewBuffer(bytesNewBody)) go func() { defer func() { err := recover() if err != nil { fmt.Println(err) } }() //调用次数统计 if err := service.CallCounts(proxyData); err != nil { fmt.Println(err) } if resp.StatusCode < 400 { service.RecordCall(proxyData, resp.StatusCode, nil) } else { service.RecordCall(proxyData, resp.StatusCode, nil) } }() //是否需要屏蔽敏感字段 仅对数据服务生效 其它服务部进行处理 //if sensitiveflag && proxyData.DataServiceType1 == 5 { // res = service.SensitiveFilter(proxyData, res) //} //计次 //bgn := time.Now() //fmt.Println(`开始携程:`, bgn) //go service.CallCounts(proxyData) //end := time.Since(bgn) //fmt.Println("结束携程: ", end) //err = service.CallCounts(proxyData) //if err != nil { // Return(nil, err, resp) // return nil //} ////个人申请调用计次 //err = service.ApplyCallCounts(proxyData) //if err != nil { // Return(nil, err, resp) // return nil //} //Return(res, nil, resp) //appeT := time.Since(appT) //fmt.Println("结束: ", appeT) return nil })) if err != nil { c.JSON(500, errors.New("请求失败")) return } reqURL := testutils.ParseURI(proxyData.ReqUrl) fmt.Println(reqURL) if reqURL.RawQuery == "" { //reqURL.RawQuery = c.Request.URL.RawQuery reqURL.RawQuery = c.Request.URL.Query().Encode() } else { if c.Request.URL.RawQuery != "" { //oldQ := c.Request.URL.Query() oldQ := reqURL.Query() newQ := c.Request.URL.Query() for k, v := range newQ { if len(v) > 1 { for kk, vv := range v { if kk == 0 { oldQ.Set(k, vv) } else { oldQ.Add(k, vv) } } } else if len(v) == 1 { oldQ.Set(k, v[0]) } else { oldQ.Del(k) } } reqURL.RawQuery = oldQ.Encode() } else { reqURL.RawQuery = reqURL.Query().Encode() } } c.Request.URL = reqURL fmt.Println("c.Request.URL-------", c.Request.URL) c.Request.RequestURI = reqURL.RequestURI() fmt.Println("c.Request-------", c.Request) c.Request.Host = getHost(proxyData.ReqUrl) //发送服务ID和用户ID c.Request.Header.Set("applyuserid", proxyData.ApplyUserId) c.Request.Header.Set("applyserviceid", cast.ToString(proxyData.ServiceId)) fmt.Println("proxyData.RealUrl-------", proxyData.ReqUrl) forwarder.ServeHTTP(c.Writer, c.Request) } } func CheckStaticFile(path string) bool { if strings.HasSuffix(path, ".css") || strings.HasSuffix(path, ".js") || strings.HasSuffix(path, ".woff2") || strings.HasSuffix(path, ".jpg") || strings.HasSuffix(path, ".svg") || strings.HasSuffix(path, ".woff") || strings.HasSuffix(path, ".html") || strings.HasSuffix(path, ".ttf") { return true } return false } func getRequestURI(req *http.Request) string { //requestURI, _ := url.ParseRequestURI(req.RequestURI) // //requestURI.RawQuery path := req.URL.Path rawQuery := req.URL.RawQuery var result = "" if rawQuery == "" { result = path } else { result = path + "?" + rawQuery } return result } func Return(res interface{}, err error, Resp *http.Response) { var b []byte if err == nil { switch res.(type) { case []byte: b = res.([]byte) case interface{}: b, _ = json.Marshal(res) } } else { Resp.Header.Set("Content-Encoding", "utf-8") b = []byte(err.Error()) } //if Resp.Header.Get("Content-Encoding") == "gzip" { //Resp.Header.Set("Content-Encoding","gzip") //b = gzipCompress(&b) //} Resp.Header.Set("X-Log-By", "Apaas") Resp.Header.Set("Content-Length", strconv.Itoa(len(b))) Resp.Body = ioutil.NopCloser(bytes.NewBuffer(b)) } func gzipCompress(content *[]byte) []byte { var compressData bytes.Buffer gzipWriter := gzip.NewWriter(&compressData) defer gzipWriter.Close() gzipWriter.Write(*content) gzipWriter.Flush() return compressData.Bytes() } // 获取域名 protocol :// hostname[:port] / path / [;parameters][?query]#fragment func getHost(httpurl string) (path string) { parse, err := url.Parse(httpurl) if err != nil { return "" } return fmt.Sprintf("%s://%s", parse.Scheme, parse.Host) } func HealthCheck(c *gin.Context) { res := model.WebRes{} res.Success = 1 res.Data = "success" c.JSON(200, res) // //apiId := c.Param("apiid") //proxyData, err := service.GetReqPath(apiId) //if err != nil { // res.Data = err.Error() // c.JSON(500, res) // return //} //var requstMethod string ////获取真实地址1GET 2POST 3 PUT 4 DELETE //if proxyData.ReqType == 1 { // requstMethod = "GET" //} else if proxyData.ReqType == 2 { // requstMethod = "POST" //} else if proxyData.ReqType == 3 { // requstMethod = "PUT" //} else if proxyData.ReqType == 4 { // requstMethod = "DELETE" //} //header := make(map[string]string, 0) //resp, err := tools.ProxySendRes(c.Request, requstMethod, proxyData.ReqUrl, "", header) //if err != nil { // res.Data = err.Error() // c.JSON(500, res) // return //} //fmt.Println(resp) //if resp.StatusCode < 400 { // res.Data = "success" //} else { // res.Data = "fail" //} //res.Success = 1 ////请求真实地址根据返回状态码判断是否服务可用 //c.JSON(200, res) //return }