最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
解決phppost而gin收不到問題-創(chuàng)新互聯(lián)
緣由

php 這邊用 post+json 形式向 golang 的 gin 框架發(fā)送數(shù)據(jù),之前網(wǎng)頁版都是使用正常,最近有個(gè)需求是一個(gè)功能接入移動(dòng)端內(nèi)部辦公系統(tǒng),通過接入 sdk 調(diào)用實(shí)現(xiàn)網(wǎng)頁上的功能。

創(chuàng)新互聯(lián)專業(yè)成都做網(wǎng)站、網(wǎng)站制作,集網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)、網(wǎng)站制作于一體,網(wǎng)站seo、網(wǎng)站優(yōu)化、網(wǎng)站營(yíng)銷、軟文推廣等專業(yè)人才根據(jù)搜索規(guī)律編程設(shè)計(jì),讓網(wǎng)站在運(yùn)行后,在搜索中有好的表現(xiàn),專業(yè)設(shè)計(jì)制作為您帶來效益的網(wǎng)站!讓網(wǎng)站建設(shè)為您創(chuàng)造效益?,F(xiàn)象

php 作為業(yè)務(wù)代理層,會(huì)接收客戶端傳過來的數(shù)據(jù),然后通過封裝的 curl 庫發(fā)送給 golang 微服務(wù)。但是這次在接收到 sdk 的發(fā)過來的數(shù)據(jù),組裝加工并轉(zhuǎn)發(fā)到 gin 時(shí),卻一直報(bào)錯(cuò)。

"Key: 'SubmitReq.TaskID' Error:Field validation for 'TaskID' failed on the 'required' tag
 
Key: 'SubmitReq.ResultStatus' Error:Field validation for 'ResultStatus' failed on the 'required' tag"

熟悉 gin 的童鞋就應(yīng)該知道,這是 shouldBind 報(bào)出的,也就是 SubmitReq 這個(gè)結(jié)構(gòu)里有兩個(gè)必傳字段,但是在接收時(shí),卻沒有收到,因此報(bào)錯(cuò)。

type SubmitReq struct {TaskID       string                 `form:"taskId" json:"taskId" binding:"required"`
	ResultStatus int64                  `form:"resultStatus" json:"resultStatus" binding:"required"`
}

var submitReq structure.submitReq
if err := c.ShouldBind(&submitReq); err != nil {rsp.Errno = config.ErrnoParams
	rsp.Errmsg = err.Error()
	c.JSON(http.StatusOK, rsp)
	return
}
解決

首先是完善 gin 入口那的接收 http 請(qǐng)求日志

log.Infof("_com_request_in||%v||from=%v||uri=%v||url=%v||method=%v||contentType=%v||header=%+v||args=%v", traceInfo, c.ClientIP(), c.Request.URL.Path, c.Request.URL, c.Request.Method, c.Request.Header.Get("Content-Type"), c.Request.Header, string(data))

接下來就是模擬發(fā)送了,并通過三次發(fā)送,定位到了問題。

最開始,模擬實(shí)際情況,先到 php 服務(wù)上找到當(dāng)時(shí) sdk 發(fā)過來的日志,然后拿到發(fā)送的數(shù)據(jù),模擬發(fā)送,在 gin 服務(wù)上發(fā)現(xiàn)日志中的 method 為 post,而 contentType 和 args 都為空,這就很有問題。

翻了翻源碼,發(fā)現(xiàn) contentType 為空時(shí),會(huì)按照下載邏輯處理。實(shí)際上,就是不處理參數(shù),接收值為空,也就報(bào)上述的錯(cuò)誤了。

func parsePostForm(r *Request) (vs url.Values, err error) {if r.Body == nil {err = errors.New("missing form body")
		return
	}
	ct := r.Header.Get("Content-Type")
	// RFC 7231, section 3.1.1.5 - empty type
	//   MAY be treated as application/octet-stream
	if ct == "" {ct = "application/octet-stream"
	}
	ct, _, err = mime.ParseMediaType(ct)
	switch {case ct == "application/x-www-form-urlencoded":
		var reader io.Reader = r.Body
		maxFormSize := int64(1<<63 - 1)
		if _, ok := r.Body.(*maxBytesReader); !ok {	maxFormSize = int64(10<< 20) // 10 MB is a lot of text.
			reader = io.LimitReader(r.Body, maxFormSize+1)
		}
		b, e := io.ReadAll(reader)
		if e != nil {	if err == nil {		err = e
			}
			break
		}
		if int64(len(b)) >maxFormSize {	err = errors.New("http: POST too large")
			return
		}
		vs, e = url.ParseQuery(string(b))
		if err == nil {	err = e
		}
	case ct == "multipart/form-data":
		// handled by ParseMultipartForm (which is calling us, or should be)
		// TODO(bradfitz): there are too many possible
		// orders to call too many functions here.
		// Clean this up and write more tests.
		// request_test.go contains the start of this,
		// in TestParseMultipartFormOrder and others.
	}
	return
}

第二次,找到 php 中 curl 填充 header 的 Content-Type 處的代碼,發(fā)現(xiàn)有邏輯漏洞

if (!empty($userInfo)) {$headerContentType = !empty($contentType) ? $contentType : $_SERVER['HTTP_CONTENT_TYPE'];
    $ctx->extHeaders = ["userinfo: " . json_encode($userInfo, JSON_UNESCAPED_UNICODE), "Content-Type: " . $headerContentType];
}

如果上游接口中,傳了$userInfo但是$contentType為空,這時(shí)$_SERVER['HTTP_CONTENT_TYPE']若為空,就是最開始時(shí)的錯(cuò)誤。后來通過打印 php 的日志也發(fā)現(xiàn)了這點(diǎn),Content-Type 確實(shí)為空。

于是,補(bǔ)充了下相關(guān)邏輯,加上了application/json; charset=utf-8,并發(fā)送了模擬請(qǐng)求。不過依然是第一次報(bào)的錯(cuò)誤。

第三次,仔細(xì)看了下 gin 打印的日志,終于發(fā)現(xiàn)了端倪,在 method 是 POST,Content-Type 是application/json; charset=utf-8情況下,參數(shù) args 為

taskId=1&resultStatus=1

本來應(yīng)該要傳 json 格式的,可傳的是 form 形式的(也可以說是 queryString 的)。雖然, gin 支持 json、form 和 queryString 三種格式數(shù)據(jù)解析,但是在 method 和 header 頭類型都確定的情況下,沒傳 json ,而是其他格式的,難怪會(huì)解析報(bào)錯(cuò)。

func (jsonBinding) Bind(req *http.Request, obj interface{}) error {if req == nil || req.Body == nil {return fmt.Errorf("invalid request")
	}
	return decodeJSON(req.Body, obj)
}

問題,還是出現(xiàn)在 php 封裝的 curl 代碼那

curl_setopt($ci, CURLOPT_POSTFIELDS, is_string($params) ? $params : http_build_query($params));

原來最后發(fā)送數(shù)據(jù)這里,是不管前面設(shè)置啥 Content-Type 的,由于前面?zhèn)鞯氖菙?shù)組,這里肯定會(huì)以 form 形式傳過去的。

解決,也很簡(jiǎn)單,就是在上游收斂了傳的 Content-Type 和 params 數(shù)據(jù),這樣就不會(huì)出現(xiàn)掛羊頭賣狗肉的情形了。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


分享題目:解決phppost而gin收不到問題-創(chuàng)新互聯(lián)
文章分享:http://fisionsoft.com.cn/article/djdscs.html