blobstore.ParseUpload在开发服务器和部署中的行为有所不同

I'm trying to send a multipart/form with both a file and an access token, it works fine with the dev server, but the exact same post to AppEngine deployment result in a different received token string (I can see that its length is a longer. 938 chars when its supposed to be 902).

I'm actually executing the exact same POST request:

curl -X POST --form "token=<ACCESS_TOKEN>" --form "file=@myfile.jpg" http://upload_url

the upload response handler:

c := appengine.NewContext(r)

blobs, values, err := blobstore.ParseUpload(r)

if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}

files := blobs["file"]

if len(files) == 0 {
    fmt.Fprintln(w, "No file uploaded")
    return
}

token := values.Get("token")

EDIT: I tried to simply create an endpoint for posting the token and printing its length, which returns the correct length.. what am I doing wrong ?

func t(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "%d", len(r.FormValue("token")))
}

EDIT2: when I print the received token from the AppEngine deployment I get something like:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImZjZmQ4NGYxZGZhN2NiODUyMTg4MDFkNDRjNzYwNDFmMzB=
lMzg2OGIifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXVkIjoiMjEwMTAyMTk5NDI=
4LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwidG9rZW5faGFzaCI6IklQMmduQjFsZGMwTE=
VEdVg5LWlZa2ciLCJhdF9oYXNoIjoiSVAyZ25CMWxkYzBMRUR1WDktaVlrZyIsImlkIjoiMTA5O=
.
.

it has line breaks... for some reason the dev server doesn't behave like that and doesn't split the lines.

how can I get the original string or stop this behavior ?

How about using multiplart.Reader?

c := appengine.NewContext(r)
if r.Method != "POST" {
    http.Error(w, "invalid request", 400)
    return
}
ct := r.Header.Get("Content-Type")
if strings.SplitN(ct, ";", 2)[0] != "multipart/form-data" {
    http.Error(w, "invalid request", 40400)
    return
}
_, params, err := mime.ParseMediaType(ct)
if err != nil {
    http.Error(w, "invalid request", 400)
    return
}
boundary, ok := params["boundary"]
if !ok {
    http.Error(w, "invalid request", 400)
    return
}
reader := multipart.NewReader(r.Body, boundary)
var data []byte
for {
    part, err := reader.NextPart()
    if part == nil || err != nil {
        break
    }
    if part.FormName() != "file" {
        continue
    }
    v := part.Header.Get("Content-Disposition")
    if v == "" {
        continue
    }
    d, _, err := mime.ParseMediaType(v)
    if err != nil {
        continue
    }
    if d != "form-data" {
        continue
    }
    data, _ = ioutil.ReadAll(part)

    // do something using data
}