2017-11-29 13 views
-2

http.RequestBody에 여러 번 액세스하고 싶습니다. 처음으로 내 인증 미들웨어에서 발생하고,이를 사용하여 sha256 서명을 다시 만듭니다. 두 번째 시간이 지나면 JSON으로 구문 분석하여 내 데이터베이스에서 사용합니다.http.Request.Body를 여러 번 읽을 수있는 적절한 방법은 무엇입니까

io.Reader (또는이 경우 io.ReadCloser)에서 두 번 이상 읽을 수 없다는 것을 알고 있습니다. 먼저 본문을 읽을 때

, 당신은 당신이 그것으로 완료되면, 당신은 원래의 데이터로 구성 요청 본문과 같은 새로운 io.ReadCloser을 설정할 수 있도록 보관해야한다 : 나는 해결책을 가진 answer to another question 발견 . 따라서 체인에서 진행할 때 다음 처리기가 동일한 본문을 읽을 수 있습니다.

그런 다음 예에서 그들은 새로운 io.ReadCloserhttp.Request.Body을 설정
// And now set a new body, which will simulate the same data we read: 
r.Body = ioutil.NopCloser(bytes.NewBuffer(body)) 

Body에서 읽고 다음 내 미들웨어의 각 단계에서 새로운 io.ReadCloser 비싼 것 같습니다 설정. 정확합니까?

덜 지루하고 값 비싸지 않게하기 위해 a solution described here을 사용하여 요청의 값인 Context()에 파싱 된 바이트 배열을 숨겨 넣습니다. 내가 원하는 때마다 그 바이트의 배열로 이미 나를 기다리고 :

type bodyKey int 
const bodyAsBytesKey bodyKey = 0 

func newContextWithParsedBody(ctx context.Context, req *http.Request) context.Context { 
    if req.Body == nil || req.ContentLength <= 0 { 
     return ctx 
    } 

    if _, ok := ctx.Value(bodyAsBytesKey).([]byte); ok { 
     return ctx 
    } 

    body, err := ioutil.ReadAll(req.Body) 
    if err != nil { 
     return ctx 
    } 

    return context.WithValue(ctx, bodyAsBytesKey, body) 
} 

func parsedBodyFromContext(ctx context.Context) []byte { 
    if body, ok := ctx.Value(bodyAsBytesKey).([]byte); ok { 
     return body 
    } 

    return nil 
} 

나는 주위에 새로운 매번 읽는 것보다 저렴 단일 바이트 배열을 유지하는 것 같은 느낌. 정확합니까? 내가 볼 수없는이 해결책에 함정이 있습니까?

+0

본문을'bytes.Reader' 또는'bytes.Buffer'에 넣는다면 기본적으로 같은 캐시 된 바이트 슬라이스를 유지하는 것입니다. 'ReadAll'로 복사하지 않으려 고하십니까? – JimB

+0

@JimB'ReadAll'은'Body'에서 모든 것을 읽는 가장 간단한 방법이었습니다 –

+1

왜 바이트 슬라이스를 다시 몸에 넣는 것이 비싸다고 생각하니? 그 사본이나 다른 것을 피하려고합니까? 'Reader'와'Closer'에서 단순히 바이트 슬라이스를 감싸는 것은 컨텍스트 메소드보다 비싸지 않습니다. 복사본을 피하려면 간단한 유형을 만들어 본문의 바이트에 직접 액세스하십시오. – JimB

답변

0

"저렴합니까?" 아마, 당신이보고있는 자원에 따라 다르 겠지만, 당신은 당신의 특정 어플리케이션을 벤치 마크하고 비교하여 확실하게 알아야합니다. 함정이 있습니까? 함정에는 모든 것이 있지만, 특히 나에게 "위험한"것처럼 보이지는 않습니다. 컨텍스트 값은 컴파일 타임 유형 검사의 손실과 복잡성의 증가 및 가독성의 손실로 인해 문제에 대한 형편없는 해결책입니다. 특정 상황에서 어떤 트레이드 오프를 만들지 결정해야합니다.

처리기가 시작되기 전에 해시를 완료 할 필요가없는 경우 다른 리더 (예 : io.TeeReader)에 본문 판독기를 래핑하여 JSON을 언 마샬 할 때 래퍼가 서명 해시를 읽고 계산합니다. 그게 "싸다"는거야? 알고있는 벤치 마크를 &에 비교해야합니다. 더 낫니? 귀하의 상황에 전적으로 달려 있습니다. 고려할 가치가있는 선택 사항입니다.