1. Quramy

    Posted

    Quramy
Changes in title
+JBossのRESTEasyにおけるMultipart Requestの文字化け対策
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,104 @@
+仕事で若干困ったのと、文字化け系の現象なのだが、同内容の対応についての日本語ページがまったく引っ掛からなかったので、メモしておく.
+
+### 背景
+
+やろうとしていたことは、↓.
+
++ `multipart/form-data`でJAX-RS(JBoss EAP 6.2, RestEASY)にファイルをUpload.
++ フォームデータには日本語を許可.
+
+コードのイメージは下記な感じだ.
+
+```java:FileResource.java
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
+
+@Path("/file")
+public class FileResource {
+
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response create(@MultipartForm UploadData uploadData){
+
+ String fileName = uploadData.getFileName(); // ★ こいつが文字化!
+ // 色々処理...
+ return Response.ok().build();
+ }
+}
+```
+
+```java:UploadData.java
+public class UploadData implements Serializable{
+ private String fileName;
+ private byte[] fileBody;
+ public String getFileName() {
+ return fileName;
+ }
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+ public byte[] getFileBody() {
+ return fileBody;
+ }
+ public void setFileBody(byte[] fileBody) {
+ this.fileBody = fileBody;
+ }
+
+
+}
+```
+
+RESTEasyの拡張アノテーション`@MultipartForm`でデータの取得をしようとするも、日本語を含む項目が悉く文字化けする.
+
+## 原因
+
+仕方なく、multipart関連のProvider実装(org.jboss.resteasy:resteasy-multipart-provider:2.3.6-final)のソースを読んでみたところ、`org.jboss.resteasy.plugins.providers.multipart.InputPart` のJavadocに下記が書いてあった.
+
+```java
+ /**
+ * If there is a content-type header without a charset parameter, charset=US-ASCII
+ * is assumed.
+ * <p>
+ * This can be overwritten by setting a different String value in
+ * {@link org.jboss.resteasy.spi.HttpRequest#setAttribute(String, Object)}
+ * with this ("resteasy.provider.multipart.inputpart.defaultCharset")
+ * String as key. It should be done in a
+ * {@link org.jboss.resteasy.spi.interception.PreProcessInterceptor}.
+ * </p>
+ */
+ static final String DEFAULT_CHARSET_PROPERTY = "resteasy.provider.multipart.inputpart.defaultCharset";
+```
+
+要は、「multipartの各partについて、content-type=○○; charset=... のようなヘッダが無い場合, ProviderはUS-ASCIIで文字コード変換するよ」という内容だ.
+
+### 対応方法
+JavaDocにも書いてある通り、`org.jboss.resteasy.spi.HttpRequest#setAttribute`に `"resteasy.provider.multipart.inputpart.defaultCharset"`をセットする方法でやってみたところ、無事解決(なお、後からこのキー名でググってみたら、JavaDocだけでなく、RESTEasy本家のドキュメントにも記載がありました...).
+
+```java:ContentTypeSetterPreProcessorInterceptor.java
+import org.jboss.resteasy.plugins.providers.multipart.InputPart;
+
+@Provider
+@ServerInterceptor
+public class ContentTypeSetterPreProcessorInterceptor implements
+ PreProcessInterceptor {
+
+ public ServerResponse preProcess(HttpRequest request,
+ ResourceMethod method) throws Failure, WebApplicationException {
+ request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, "UTF-8");
+ return null;
+ }
+
+}
+```
+
+`PreProcessInterceptor`は http://docs.jboss.org/resteasy/docs/2.3.6.Final/userguide/html_single/index.html#PreProcessInterceptors にもある通り、RESTEasyのリクエスト時に `HttpRequest`への拡張ポイントとして利用できる. `@Provider`が付与されていれば、勝手にJBossがInterceptorとして登録してくれるため、特に設定ファイル等の記載は不要.
+
+### 参考リンク
++ RESTEasyのドキュメント http://docs.jboss.org/resteasy/docs/2.3.6.Final/userguide/html_single/index.html#multipart_overwrite_default_charset
++ 関連JavaDoc
+https://docs.jboss.org/resteasy/docs/2.3.6.Final/javadocs/org/jboss/resteasy/plugins/providers/multipart/InputPart.html