utf-8をフォームからJAX-RS(REST)に転送する際の問題

はじめに



Webアプリケーションインターフェイスからデータを転送する方法はいくつかありますが、おそらく最も一般的なのは、MIMEタイプのapplication/x-www-form-urlencoded



フォームを送信することです。 別のオプションはmultipart/form-data



です。



MVCフレームワークのコントローラーは、受信用のサーバーテクノロジーとして使用できます( Spring MVCJava Server PagesJava Server Facesは、主要なJavaテクノロジーから言及する必要があります。しかし、これらのフレームワークは、Javaまたはニーズフレームワークが許可するものから離れたステップ。RESTインターフェースをアプリケーションのバックエンドに公開する場合、フロントエンド開発は単純化されます。 onizatora選択肢が大幅に拡大: Apacheの速度FreeMarkerのトゥルービュー/コントローラに関連付けされ、その後、サーバー側でフォームデータをビーナで書かれているが(Spirng MVCはよく最新に統合することを言及する価値がある)、JSFはまた、遺伝的問題を観察しました。..エンコーディングについては、別の記事のトピックを検討します。



JAX-RSの簡単な紹介は、 前の記事で説明しました 。 また、JAX-RSを介して公開されるインターフェースは、フォームデータを使用してGET



およびPOST



リクエストを受け入れることができます。 この記事では、非latin-1



を使用する場合のこのアプローチの問題について説明します。





JAX-RSでのフォームデータの取得



フォームからメソッドにパラメーターを注入するためのアノテーションがいくつかあります: @Form



@FormParam



POST



要求の場合、 @FormParam



GET



in動作の@FormParam



同等です。 小さな例外を除いて:utf-8使用時の動作。 GET



メソッドを使用する場合、 urlencoded



から文字列へのデコードは問題なく発生します。 POST



Content-Type



charset=utf-8



を指定するPOST



も必要です。これにより、 urlencoded



からデコードするときurlencoded



、バイトストリームがLatin-1ではなくUTF-8に変換されます(デフォルトの動作)。



ブラウザ


ブラウザ(またはjqueryなど)はエンコーディングを指定しないため、古いUTF-8 CPが含まれている場合、フォームフィールドの値が誤って解釈されます。 Content-Type: application/x-www-form-urlencoded; charset=utf-8



ヘッダーを明示的に指定することにより、jqueryを使用する場合、この問題は回避されます。application Content-Type: application/x-www-form-urlencoded; charset=utf-8



Content-Type: application/x-www-form-urlencoded; charset=utf-8



。 jsのないフォームの場合、フォームにenctypeを指定して成功しませんでした。



Jboss resteasy


もちろん、疑問が生じます。データが他のアプリケーションから取得される場合は、 Form注釈を使用する必要がありますか? 私たちの場合、その使用はDRYの原則から正当化されます。同じメソッドをクライアントフォームとこのAPIを使用する外部アプリケーションの両方で使用できます。



Resteasyクライアントフレームワークを使用する場合、いくつかのオプションが可能です。 たとえば、必要なメソッドに@HeaderParam("Content-Type")



を追加できます。



 @Path("/") public interface Rest { @POST @Path("test") public String test(@FormParam("q") String query, @HeaderParam("Content-Type") String contentType); }
      
      







使用法は次のようになります。



 Rest client = ProxyFactory.create(Rest.class, url); client.test(query, "application/x-www-form-urlencode; charset=utf-8");
      
      







ただし、 Content-Type: application/x-www-form-urlencoded



ヘッダーにcharset



フィールドを追加するクライアントインターセプターを使用する方がより正確で便利です。 次のように実装されます。



 @ClientInterceptor @HeaderDecoratorPrecedence public class RestInterceptor implements ClientExecutionInterceptor { public static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"; public static final String FORM_CONTENT_TYPE_WITH_CHARSET = "application/x-www-form-urlencoded; charset=utf-8"; @Override public ClientResponse execute(ClientExecutionContext context) throws Exception { String contentType = context.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); if (formWithoutCharset(contentType)) { context.getRequest().header(HttpHeaders.CONTENT_TYPE, FORM_CONTENT_TYPE_WITH_CHARSET); } return context.proceed(); } private boolean formWithoutCharset(String contentType) { return contentType != null && contentType.contains(FORM_CONTENT_TYPE) && ! contentType.contains("charset"); } }
      
      







もちろん、インターセプターのこのバリアントは理想的ではありません。 latin-1



フォームを送信したい可能性があります...しかし、これはクライアントコードを簡素化する最初のステップです。



有効にするには、フレームワークの初期化手順をわずかに修正する必要があります。



 public static void initResteasy() { ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance(); RegisterBuiltin.register(factory); InterceptorRegistry<ClientExecutionInterceptor> registry = factory.getClientExecutionInterceptorRegistry(); registry.register(new RestInterceptor()); }
      
      







その後、 ClientRequest



を使用するとき、およびリクエストの送信プロセスでプロキシオブジェクトを使用するとき、 application/x-www-form-urlencoded



Content-Type



ヘッダーがあり、 charset



がない場合、それを含むヘッダーが付加されます。



All Articles