2016-04-02 2 views
2

Я пишу приложение, которое будет использовать Watson Natural Language Classifier («NLC»). Когда я отправить запрос HTTP POST против v1/classifiers URI path со следующей тела сообщения запроса, сервер отвечает кодом состояния 415 (Unsupported Media Type):Как отправить данные о множественной форме в HTTP-запросе (для обучения Watson NLC)?

--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"} 

Код состояния 415 предполагает проблемы с содержанием тип, но это кажется, как и все MIME-типы.

Мой код (написанный в 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 
} 
+0

Кроме того, данный запрос curl (curl -u "{username}": "{password}" -F [email protected] -F training_metadata = "{\" language \ ": \" en \ ", \ "name \": \ "My Classifier \"} "" https://gateway.watsonplatform.net/natural-language-classifier/api/v1/classifiers ") отлично работает. –

ответ

1

Обратите внимание, что локон посылает "Content-Type" заголовок из multipart/form-data. Ваша программа Go отправляет заголовок «Content-Disposition» только с form-data (обратите внимание на разницу: в нем отсутствует ведущий составной тип верхнего уровня multipart), но он не позаботится о отправке правильного заголовка «Content-Type» для содержащего HTTP-запроса.

Его multipart.Writer типа по CreateFormFile method does the same, но опять же, это только части работы:

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

Чтобы получить правильное "Content-Type" значение заголовка, вы должны использовать multipart.Writer.FormDataContentType. Чтобы поместить это значение в использовании, вам нужно, чтобы получить ваш multipart.Writer в ваш метод WatsonClassifier.request, так что вы можете установить тип контента на вашем http.Request Например:

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

В качестве альтернативы, добавить еще один параметр в WatsonClassifier.request для содержания type и передать результат FormDataContentType в качестве аргумента с сайта вызова в WatsonClassifier.Train.

Сообщите нам, если это трюк.