grpc服務端轉換protobuf到http請求參數query


前提

grpc服務接收到request的請求后,需要把參數轉換成http,去請求其他接口。

使用go作為grpc的服務端,數據協議是protobuf

想到的幾種解決方案:

  • 1.編譯好的pb.go文件里有個string(),可以把所有參數都打印出來,參數之間是空格隔開的,參數和值是k:v的形式,但是不帶引號,不是json格式

  • 2.把接收到的數據轉換為json,直接以json的格式,發送請求

  • 3.根據傳過來的request反射到固定的struct上,得到具體的屬性和獲取此屬性的方法,再加入到url.values{},再encode()發送請求

實現

方案1

方案1是比較簡單的,用空格分割,得到參數和值,再根據":"分割得到參數、值,再加入到url.values{}

代碼如下:

param := url.Values{}
//得到請求的字符串形式
rs := strings.Split(request.String(), " ")
	for _, v := range rs {
		if v != "" {
			vv := strings.Split(v, ":")
			param.Add(vv[0], strings.Trim(vv[1], "\""))
			vv := strings.SplitN(v, ":", 2)
			//轉換成
			val, e := strconv.Unquote(vv[1])
			log.Print(val, e)
			if e == nil {
				param.Add(vv[0], val)
			}
		}
	}


前期運行OK,后期遇到了兩個問題:

  • 1.提交的值里有空格時,分割會有問題
  • 2.得到的中文是utf8字符

放棄方案1

方案2

把數據先轉成json,再解析成map[string]string 的形式,目的是為了省去值都轉換為string

str, _ := json.Marshal(request)
	jsonstr := string(str)

	m := make(map[string]interface{})
	e := json.Unmarshal([]byte(jsonstr), &m)
	param := url.Values{}
	if e != nil {
		return param
	}

	for k, v := range m {
		sv := fmt.Sprint(v)
		param.Add(k, sv)
	}

結果:對於中文還有空格的問題是解決了,不過會把int64的數字類型轉換成float類型,轉換有問題

方案3

根據go的reflect包反射出實際的struct,go編譯pb的文件里struct里屬性名和proto文件不一樣,需要根據屬性的tag得到實際的參數名

代碼如下:

	ty := reflect.TypeOf(request).Elem()
	#得到struct的屬性數量
	fieldnum := ty.NumField()
	
	#實際數據的指針
	ob := reflect.ValueOf(request)
	param := url.Values{}
	#由於編譯好的屬性最后3位不用
	for i := 0; i < fieldnum-3; i++ {
		f := ty.Field(i).Tag.Get("json")
		fv := strings.Split(f, ",")
		k := fv[0]

		fieldname := ty.Field(i).Name
		ret := ob.MethodByName("Get" + fieldname).Call(nil)
		if !ret[0].IsZero() {
			# 這一步,用了很巧的辦法把各個類型轉換成了string才能加入到param里
			v := fmt.Sprint(ret[0])
			param.Add(k, v)
		}
	}
	return param


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM