CLOVER🍀

That was when it all began.

GroovyのHTTPBuilderで、multipart/form-dataを送信する

先ほど公開した、W3C Markup Validation ServiceとW3C CSS Validation Serviceを使った検証を自動化した際に、ハマったのがこれ。

このサービスには、multipart/form-dataでPOSTする必要があります。

例えば、W3C CSS Validation Serviceを使う時は、こんなデータを送信する必要があります。

Content-Type: multipart/form-data; boundary=---------------------------1490267287501179803520268259
Content-Length: 1066

-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="text"

html {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  background-repeat: no-repeat;
  background-position: center top
  background-attachment: fixed;

  font-siz: 12px;
  color: midnightblue;
}

-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="profile"

css3
-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="usermedium"

all
-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="type"

none
-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="warning"

1
-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="vextwarning"


-----------------------------1490267287501179803520268259
Content-Disposition: form-data; name="lang"

ja
-----------------------------1490267287501179803520268259--

「multipart/form-data; boundary=」が入っているのが、特徴ですね。

これをGroovyのHTTPBuilderで送信する方法が最初わからなくて、四苦八苦していました。

最終的に、Apache HttpComponentsのhttpmimeを使えばよいとわかったので、それで実装。

import java.nio.charset.StandardCharsets

@Grab('commons-codec:commons-codec:1.9')
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.6')
@GrabExclude('commons-codec:commons-codec')
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method

@Grab('org.apache.httpcomponents:httpmime:4.2.1')
import org.apache.http.entity.mime.HttpMultipartMode
import org.apache.http.entity.mime.MultipartEntity
import org.apache.http.entity.mime.content.StringBody
import org.apache.http.util.EntityUtils

def url = 'アクセスするURL'

def http = new HTTPBuilder(url)

def resp = http.request(Method.POST) { req ->
    def entity = new MultipartEntity()
    entity.addPart('パラメータ名', new StringBody('送信する値', StandardCharsets.UTF_8)) }
    req.entity = entity
}

必要な部分だけ抜き出すと、こんな感じになります。

httpmimeのバージョンは最新版ではないのですが、HTTPBuilderが依存しているHttpComponentsのバージョンから、こちらに合わせておきました。

MultipartEntityにaddPartしている値やCharsetの指定は、適宜読み替えてくださいね。

あと、話はそれますが、地味にハマったのがここ。

@Grab('commons-codec:commons-codec:1.9')
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.6')
@GrabExclude('commons-codec:commons-codec')
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method

最初は会社でスクリプトを書いていたのですが、GrabExcludeして別途依存関係を追加しないと

org.codehaus.groovy.control.MultipleCompilationErrorsException

みたいなエラーを吐いてコケてくれます。同じ事象で、ハマった方もいらっしゃったようで。

GroovyでHTTPBuilderをGrabしようとしたらエラー
http://d.hatena.ne.jp/kaakaa_hoe/20120824

前に自宅でやった時は何も起こらなかったので、事前にCommons Codec 1.6をGrapeで解決したことがあったんでしょうね。

今回はGrabExcludeしてCommons Codecのバージョンを上げて脱出しました。本来1.6を指定すべきなのですが、どうやっても依存関係の解決ができませんでした。

Grapeを使っていて、たま〜にハマるのでこういうのに遭遇すると、ちょっとつらいです。そもそも、簡単なスクリプトで使うつもりなので、ある程度書き上げた後に試して動かない、みたいな…。