サーバーとの通信
第3回 HTTPService を利用する(2)

HTTPService - データをサーバーに送る

HTTPService タグを使ってサーバーと通信をするための考え方、および方法を説明します。今回は、サーバーへデータを送る方法を見ていきます。

 


目次

サーバーにデータを送る

  • method プロパティー
  • request プロパティー
  • contentType プロパティー

HTTPService タグでサーバーにデータを送るとは?

HTTPService タグを使ってサーバーにデータを送る場合、データはHTTPリクエストの GET/POST パラメータとして送ることになります。 送信データの受け取り側は Servlet / JSP や PHP、ASP、ColdFusion などの Webアプリケーションのサーバーサイドテクノロジーを使って実装します。

送信データの設定の仕方

まずは簡単な例を見てみます。次の例は サーバーにユーザーが入力した文字を送ります。サーバーは現在時刻とクライアントから送られた文字を送り返し、クライアントはその文字を受信、表示します。

 ユーザーが入力した文字をサーバーに送るアプリケーション - http_basic_send1_1.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
  <mx:Script>
<![CDATA[
	function sendData() {
		var obj = new Object();
		obj.inp = mytext.text;
		srv.send(obj);
	}
	
	function gotResult(event) {
		res.text = srv.result.echo;
	}
]]>
</mx:Script>

<mx:HTTPService id="srv" url="echo1.jsp" result="gotResult(event)" />

  <mx:Label text="Input data"/>
  <mx:TextInput id="mytext" width="400" />
  <mx:Button label="Send data" click="sendData()" />
  <mx:Label text="Data From server"/>
  <mx:TextInput id="res" width="400" editable="false" />
</mx:Application>

 クライアントから送られてきたデータに時間情報を付加して応答するJSP - echo1.jsp

<%@ page contentType="application/xml; charset=utf-8" %>
<% 
	request.setCharacterEncoding("utf-8");
	String in = request.getParameter("inp");
	
	String res = new java.util.Date() + " : " + in;
	System.out.println("Client send data:" + in);
%>
<echo><%= res %></echo>  

 実行結果例

HTTPService タグを使ってサーバにデータを送る場合、送信するデータの渡し方には2つの方法があります。 request プロパティーを使う方法と、send ファンクションの引数で渡す方法です。もし両方に値が設定されている場合は send ファンクションの引数が優先されます。 上の例では send ファンクションの引数でデータを送出しています。 送信したデータは JSP で受け取っています。 アプリケーションが送ったデータは JSPからみると reuqest オブジェクトの中に入っています。 JSP ページの中で

<% String cdata = getParameter("パラメータ名");  %>

と書けばクライアントが送ったデータを受け取ることができます。ここでパラメータ名は Flex 側では、送出するデータのプロパティー名に相当します。

var obj = new Object();
obj.パラメータ名 = mytext.text;

srv.send(obj);

sendData ファンクションを request プロパティーでデータを送るように書き換えた場合次のようになります。

function sendData() {
srv.request.パラメータ名 = mytext.text;
srv.send();
}

またHTTPService タグの記法で、次のようにして request プロパティーを設定することも可能になっています。(この場合、sendData ファンクションは srv.send(); の処理を行うだけです。)

<mx:HTTPService id="srv" url="echo1.jsp" result="gotResult(event)" >
<mx:request>
<パラメータ名>{mytext.text}</パラメータ名>
</mx:request>
</mx:HTTPService>

いずれの記法を使うにしても、複数のデータを一度に送りたいならば、複数のプロパティーを送信オブジェクトに設定します。 送信データが多くなると、これを論理的にまとめて、アプリケーション・ビューとサーバーと交換されるデータを別々の物として管理したくなります。このような目的でデータを <mx:Model> タグで論理的にまとめることがよくあります。 http_basic_send1_1.mxml を例に、送信データを <mx:Model> タグで論理的にまとめると、次のように書き換えることができます。

 モデルを使ってデータを論理的にまとめる例: http_basic_send1_2.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
  <mx:Script>
<![CDATA[
	function sendData() {
		srv.send();
	}
	
	function gotResult(event) {
		res.text = decode(srv.result.echo);
	}
]]>
</mx:Script>
<mx:Model id="mydata">
<inp>{mytext.text}</inp>
</mx:Model>

<mx:HTTPService id="srv" url="echo1.jsp" result="gotResult(event)" request="{mydata}" />

  <mx:Label text="Input data"/>
  <mx:TextInput id="mytext" width="400" />
  <mx:Button label="Send data" click="sendData()" />
  <mx:Label text="Data From server"/>
  <mx:TextInput id="res" width="400" editable="false" />
</mx:Application>

このようにアプリケーションをビューの部分と、データ部分で論理的に切り分ける考え方は MVC アーキテクチャーモデルからきており、アプリケーションの規模が大きいときメインテナンス性などの面で有利です。

HTMLのフォームとは違う mx:From タグ

よく勘違いするのが <mx:From> タグの存在です。HTML の <FORM> タグはその中にある入力部品の値を action プロパティーで指定された場所に送信します。しかし <mx:Form> タグの機能はこれとは異なります。 <mx:From> タグは、入力フォームのユーザーインターフェースに適した ”タイトル:入力部位品” というビューを描くことに適したコンテナーです。 <mx:Form> タグにサーバーにアクセスする機能はありません。 フォームの中の入力部品の値をまとめてサーバに送りたい場合、Model タグでこれを統合し、そのモデルオブジェクトを HTTPService で送信するなどの作りこみが必要です。

GET送信、POST送信

これまでの例ではデータはすべて GET リクエストとしてサーバーに送られていました。つまり

		var obj = new Object();
		obj.inp = mytext.text;
		srv.send(obj);

 の例で、サーバーにアクセスするとき、リクエストURLは次のように解釈されていました。

http://ホスト名/..../echo1.jsp?inp=入力したデータ  

(ただし、ここまでの例はFlexプロキシを使って通信をしているので、アプリケーション -> Flexプロキシ間は違ったURL パタンでリクエストが行われています)

GETリクエストには送信できる文字サイズに限度があるなどの欠点があります。 HTTP でサーバーにデータを送るもう一つの方法は POST リクエストでデータを送る方法です。この場合、リクエストデータはURL ではなく、HTTP リクエストヘッダーの後に続く、リクエストボディーとして送出されます。

Flex アプリケーションからのリクエストの形式をデフォルトの GET から POST に切り替えるのはとても簡単です。 <mx:HTTPService> タグのプロパティーに method というプロパティーがあります。 これを"POST" と設定したとき、リクエストは POST 形式で行われます。

 <mx:HTTPService id="srv" url="echo1.jsp" result="gotResult(event)" method="POST" />

データの受け取り側(サーバー側)は JSP の場合、変更の必要はありません、JSP の場合、リクエストが GET でなされたか POST でなされたかに関わらず、 request に対する getParameter メソッドの呼び出しで、値を取得することができます。 サーブレットの場合は GET 要求に対する処理は doGet メソッドで実装します。POST 要求に対する処理は doPost メソッドで実装します。GET / POST と サーブレット JSP について、より詳しい情報が必要でしたら J2EE / サーブレット / JSP 関連の書籍や、あなたの周りの詳しい人に聞いていただく必要があります、、

送信データの 形式(application/x-www-form-urlencoded か application/xml か)

これまでみてきたサーバーへのデータの送信ではデータは プロパティー名=値 という形サーバーに送られていました。複数のデータを送信する場合は プロパティー名1=値&プロパティー名2=値 ... という形で送られます。これは HTTP の仕様により定められた形式です。 しかし、これとは異なった形式でデータを送りたいことがあるかもしれません。例えばサーバーはクライアントから XML 形式でデータを受け取りたいかも知れません、あるいは何らかのバイナリーデータを渡したいかもしれません。このような要望に応えるためにあるプロパティーが <mx:HTTPService> タグの contentType プロパティーです。 デフォルトでは "application/x-www-form-urlencoded" と設定 されており、これまで説明したような形式でデータをサーバーに送ります。 contentType へのもう一つの有効な設定値が "application/xml" です。 この形式でデータを送る場合、データは プロパティー名=値 という形式で変更されることなく、そのままの文字列が送出されます。 このように変更した場合、これに合わせてサーバー側の処理も変更する必要があります。 request.getParameter メソッドはリクエストデータの中の プロパティー名=値 のフォーマットから情報を取り出すためのメソッドだからです。 "application/xml" 形式で送出されたデータをサーバー側で受け取るには代表的には

InputStream in = request.getInputStream();

というようにして request オブジェクトの中から InputStream オブジェクトを取り出し、これを使ってデータの読み込みをします。

これまで出てきた例をデータを "application/xml"形式で送る方法で書き換えたとき次のようになります。

 ユーザーが入力した文字を "application/xml"形式で送るアプリケーション - http_basic_send2_1.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml">
  <mx:Script>
<![CDATA[
	function sendData() {
		srv.send(mytext.text);
	}
	
	function gotResult(event) {
		res.text = srv.result.echo;
	}
]]>
</mx:Script>

<mx:HTTPService id="srv" url="echo2.jsp" 
         result="gotResult(event)" contentType="application/xml" />

  <mx:Label text="Input data"/>
  <mx:TextInput id="mytext" width="400" />
  <mx:Button label="Send data" click="sendData()" />
  <mx:Label text="Data From server"/>
  <mx:TextInput id="res" width="400" editable="false" />
</mx:Application>

 クライアントからのデータを"application/xml"形式で受け取り応答を返すJSP - echo2.jsp

<%@ page contentType="application/xml; charset=utf-8" %>
<%@ page import="java.io.*" %>

<% 
	InputStream in = request.getInputStream();
	BufferedReader r = new BufferedReader(new InputStreamReader(in, "utf-8"));
	String line = null;
	String res = "";
	while( (line = r.readLine()) != null) {
		res = res + line;
	}	
	res = new java.util.Date() + " : " + res;
	System.out.println("Client send data:" + res);
%>
<echo><%= res %></echo>

 (日本語の文字は文字化けするかもしれません。これは Flex 1.5 の既知の問題です。今後の Updater のリリースなどのタイミングで解決される可能性がありますが、現状でも次に紹介する 「URLEncode を考える」の機能を組み込めば日本語文字化けの問題は解消されます)

URLEncodeを考える

最初に紹介した http_basic_send1_1.mxml を起動してみてください。次に "<" や ">" "&" などの記号をサーバーに送ってみます。リクエストはエラーとなるはずです。これは URLEncoding の問題です。 サーバーはクライアントが送ってきたこれらの記号も含めて応答文字列を生成しますが、生成された応答データの中で、これらの文字はタグの記号であると解釈されて、結果を受け取った Flex アプリケーションは 誤ってデータを解析してしまうのです。

< > & といった記号をXMLデータの中に含めるときには、代替文字に書き換える必要があります。 Flex アプリケーションでのデータの送受信において、Flexはこの読み替えを自動的に行ないます。つまり、URLEncodeの問題は Flexアプリケーションがデータ送信し、サーバー側で処理がされるまでの間は問題とはならなりません。しかしサーバーが応答を返すとき、この問題を考慮した処理が組み込まれていないと不正な動作をすることがあります。 URLEncode の処理をサーバーサイドで組み込む方法の一つを紹介します。 java.net.URLEncoder クラスの encode() メソッドを利用します。 例えば、最初の例にあった echo1.jsp の例では最後の行を次のように書き換えます。

<echo><%= java.net.URLEncoder.encode(res) %></echo>

Flex アプリケーションサーバー側ではエンコードされた文字をデコードしなければ正しい表示となりません。 http_sernd1_1.mxml の例ですと次のようにします。

	function gotResult(event) {
res.text = unescape(srv.result.echo);
}

これに関連した問題で"application/xml"形式で日本語文字を送信したときの文字化けの問題があります。これは不具合なのですが、現状、1.送信時 escape(文字列) ファンクションを使って URLEncode を行ってからサーバーにデータを送る。 2.受信時 java.net.URLDecoder.decode(受信文字列, "utf-8") としてデコードをする。 という処理を追加することで問題を回避できます。

次回、第4回は HTTPService のエラーハンドリングのあたりを見ていきたいと 思っています。

続く


ご意見・ご感想

技術レポート一覧へ

トップページ


作成日:2005年2月21日
更新日:2005年2月21日