普通网友 2016-04-02 07:20
浏览 65
已采纳

如何在HTTP请求中发送多部分表单数据(用于Watson NLC培训)?

I'm writing application that'll use Watson Natural Language Classifier ("NLC"). When I send an HTTP POST request against the v1/classifiers URI path with the following request message body, the server responds with status code 415 (Unsupported Media Type):

--04fef47728eb08148fe9c7b18dd42b75abd75ebf752fd3412a85aa3af075
Content-Disposition: form-data; name="training_data"; filename="data.csv"
Content-Type: text/csv

How hot is it today?;temperature
Is it hot outside?;temperature
Will it be uncomfortably hot?;temperature
Will it be sweltering?;temperature
How cold is it today?;temperature
Is it cold outside?;temperature
Will it be uncomfortably cold?;temperature
Will it be frigid?;temperature
What is the expected high for today?;temperature
What is the expected temperature?;temperature
Will high temperatures be dangerous?;temperature
Is it dangerously cold?;temperature
When will the heat subside?;temperature
Is it hot?;temperature
Is it cold?;temperature
How cold is it now?;temperature
Will we have a cold day today?;temperature
When will the cold subside?;temperature
What highs are we expecting?;temperature
What lows are we expecting?;temperature
Is it warm?;temperature
Is it chilly?;temperature
What's the current temp in Celsius?;temperature
What is the temperature in Fahrenheit?;temperature
--04fef47728eb08148fe9c7b18dd42b75abd75ebf752fd3412a85aa3af075
Content-Disposition: form-data; name="training_metadata"; filename="metadata.json"
Content-Type: application/json

{"language": "en"}

The 415 status code suggests a problem with the content type, but it seems like all the MIME types are correct.

My code (written in Go):

func (w WatsonClassifier) createFormFile(writer *multipart.Writer, fieldname string, filename string, contentType string) (io.Writer, error)     {
    h := make(textproto.MIMEHeader)
    h.Set("Content-Disposition",
        fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
            fieldname, filename))
    h.Set("Content-Type", contentType)
    return writer.CreatePart(h)
}

func (w WatsonClassifier) request(method string, apiUrl string, body io.Reader) (string, error) {
    url := w.url + "/" + apiUrl
    req, err := http.NewRequest(method, url, body)
    if err != nil {
        return "", err
    }
    req.SetBasicAuth(w.username, w.password)
    client := http.Client{}
    resp, err := client.Do(req)
    if resp.StatusCode != 200 {
        answer, _ := ioutil.ReadAll(resp.Body)
        fmt.Println(string(answer))
        return "", errors.New("Watson returned wrong status code : " + resp.Status)
    }
    answer, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    return string(answer), nil
}

func (w WatsonClassifier) Train(data []ClassifierCategory) (Classifier, error) {
    table := w.buildTable(data)
    str := w.buildCsv(data)
    buf := new(bytes.Buffer)
    writer := multipart.NewWriter(buf)
    data_part, err := w.createFormFile(writer, "training_data", "data.csv", "text/csv")
    if err != nil {
        return WatsonClassifier{}, err
    }
    data_part.Write([]byte(str))
    metadata_part, err := w.createFormFile(writer, "training_metadata", "metadata.json", "application/json")
    if err != nil {
        return WatsonClassifier{}, err
    }
    metadata_json := "{\"language\": \"" + w.Language + "\"}"
    metadata_part.Write([]byte(metadata_json))
    fmt.Println(buf.String())
    answer, err := w.request("POST", "v1/classifiers", buf)
    if err != nil {
        return WatsonClassifier{}, err
    }
    fmt.Println(answer)
    return WatsonClassifier{}, nil
}
  • 写回答

1条回答 默认 最新

  • dourui9570 2016-04-02 21:49
    关注

    Note that curl is sending a "Content-Type" header of multipart/form-data. Your Go program is sending a "Content-Disposition" header with just form-data (note the difference, it lacking the leading multipart composite top-level media type), but it doesn't take care of sending the correct "Content-Type" header for the containing HTTP request.

    Go's multipart.Writer type's CreateFormFile method does the same, but again, that's only part of the job:

    h.Set("Content-Disposition",
            fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
                    escapeQuotes(fieldname), escapeQuotes(filename)))
    

    To get the proper "Content-Type" header value, you need to use multipart.Writer.FormDataContentType. To put that value to use, you'll need to get your multipart.Writer into your WatsonClassifier.request method, so that you can set the content type on your http.Request instance:

    req.Header.Set("Content-Type", writer.FormDataContentType())
    

    Alternately, add another parameter to WatsonClassifier.request for the content type, and pass the result of FormDataContentType as the argument from the call site in WatsonClassifier.Train.

    Let us know if that does the trick.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 易语言把MYSQL数据库中的数据添加至组合框
  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况