2008/02/28(木) [n年前の日記]
#1 [iappli] iアプリがサーバと通信できなくなっていて焦る
そろそろ時期的に、サーバと通信する実行バイナリを送っておかないといけない。と思って、そのような状態にしたら、通信エラーが発生。むぅ。
自宅サーバ + Apache1.3 + phpスクリプト?と通信させているはずなのだけど…。ローカルのWindows機上で動かした、04WebServer + phpスクリプトなら、するすると通信できてるように見えるのだけど。
ブラウザで、自宅サーバ側のphpスクリプトにアクセスしたら、出力結果が文字化け。自宅サーバは基本的に euc-jp で動いてるから、そのせいだろうか。と言っても、別途DLツールでDLしてみると、自宅サーバのソレも、Windows機のソレも、まったく同じバイナリを返すわけで…。
一応、.htaccess を設置して、自宅サーバ側の文字化けも解消してみたり。
ブラウザで開いた際に文字化けはしなくなったけど、iアプリ側は相変わらずエラー発生。てことは、コレじゃないな。
_[PHP-users 21861]Re: Content-Lengthヘッダの出力方法
phpスクリプトのほうを書き換えてみた。自宅サーバのソレもエラーが出なくなった。助かった。
いや、しかし、Content-Length が返ってこない場合を想定して作っておいたほうがいいのかもしれんか…?
自宅サーバ + Apache1.3 + phpスクリプト?と通信させているはずなのだけど…。ローカルのWindows機上で動かした、04WebServer + phpスクリプトなら、するすると通信できてるように見えるのだけど。
ブラウザで、自宅サーバ側のphpスクリプトにアクセスしたら、出力結果が文字化け。自宅サーバは基本的に euc-jp で動いてるから、そのせいだろうか。と言っても、別途DLツールでDLしてみると、自宅サーバのソレも、Windows機のソレも、まったく同じバイナリを返すわけで…。
一応、.htaccess を設置して、自宅サーバ側の文字化けも解消してみたり。
Options +ExecCGI AddType application/x-httpd-php .php AddDefaultCharSet Shift_JIS <Files ~ "^.(htpasswd|htaccess_custom)$"> deny from all </Files> <IfModule mod_php5.c> php_value output_handler "mb_output_handler" # PHPの記述コード系(ex. EUC-JP)を指定。 php_value mbstring.internal_encoding "SJIS" # HTTPの出力コード系(ex. SJIS)を指定。 php_value mbstring.http_output "SJIS" </IfModule>_PHP のインストール(Apache2.0 Windows編) を参考にさせてもらったり。
ブラウザで開いた際に文字化けはしなくなったけど、iアプリ側は相変わらずエラー発生。てことは、コレじゃないな。
◎ Content-Lengthが原因だった。 :
ソースの通信部分に、System.out.println( ... ) をバカスカ入れて実機で動作確認したら、どうも con.getLength() が -1 を返しているらしい。その値を元にして配列確保してるから、「配列が確保できんがな」という事態になってるのだな。
Mozilla Firefox に _LiveHTTPHeaders という Add-ons を入れて、自宅サーバの返すソレを確認。むぅ。HTTPレスポンスヘッダに Content-Length が含まれていない。APIマニュアルにも「それがない場合は -1 を返す」と書いてあった。むむむむ。
ちなみに 04WebServer のほうは Content-Length を返していた。なるほど。それで、ローカルで実験したときにはエラーが発生しないのね。
Mozilla Firefox に _LiveHTTPHeaders という Add-ons を入れて、自宅サーバの返すソレを確認。むぅ。HTTPレスポンスヘッダに Content-Length が含まれていない。APIマニュアルにも「それがない場合は -1 を返す」と書いてあった。むむむむ。
ちなみに 04WebServer のほうは Content-Length を返していた。なるほど。それで、ローカルで実験したときにはエラーが発生しないのね。
◎ _Pound 1.6 + Apache 2.0.48 + PHP 4.3.4のWebサーバにHTTP/1.0を使ってアクセスできない :
これらの端末からPoundを通してApache2から呼び出されるPHPが生成したページにアクセスすると、0バイトの空データしか取得できない。もちろんHTTP/1.1なブラウザからはデータが表示される。
原因はPoundの仕様によるものだった。HTTP/1.0の場合Content-Lengthは必須となる、にも拘らずバックエンドのApacheがContent-Lengthを含まないレスポンスをPoundに返した場合にクライアントには空データが渡される。
今回のケースではPHPの生成したページにContent-Lengthが含まれていなかった。解決策としてはPHPで出力バッファリングを使いContent-Lengthを出力するか、Poundの挙動を変更するかどちらか。
_[PHP-users 21861]Re: Content-Lengthヘッダの出力方法
ob_start() のマニュアルの例を見て、以下のようなスクリプトを作成して試してみました。 特に問題なく動いているように見えましたが、どうでしょうか。
function callback( $contents ) { $contents = mb_convert_encoding( $contents, 'SJIS-win' ); header( 'Content-Type: text/html; charset=Shift_JIS' ); header( 'Content-Length: ' . strlen( $contents ) ); return $contents; } ob_start( 'callback' );なるほど…。スクリプト側で対処できるのか。
phpスクリプトのほうを書き換えてみた。自宅サーバのソレもエラーが出なくなった。助かった。
いや、しかし、Content-Length が返ってこない場合を想定して作っておいたほうがいいのかもしれんか…?
◎ リソースフォルダ内のファイルサイズを取得する方法。 :
_CLDC+MIDP+携帯電話用Javaスレッド part 7
300 :デフォルトの名無しさん:2007/08/27(月) 01:03:53φ(..) メモメモ。
リソースフォルダに格納した
ファイルのサイズを簡単に求める方法はないでしょうか?
外部に保存されているファイルなら、
StorageConnectionの「getLength()」を使えば、
簡単にファイルサイズを求められるのですが・・・。
実際にリソースデータを読込めば、
当然そのリソースのサイズは判明しますが、
「リソースデータを読込む前」に、
リソースデータのサイズを取得する方法があれば、
是非ご教授お願い致します。
301 :デフォルトの名無しさん:2007/08/27(月) 01:20:39
InputStream#availableは?
一応読み込む前ではある。
302 :300:2007/08/27(月) 02:14:40
>>301
おお!リソースのサイズが取得できました!
レスありがとうございます。
◎ 1byteずつ読んでいったほうがいいらしい。 :
_iモード携帯電話用Java(iアプリ) Part14 - googleキャッシュ
googleキャッシュがいつ消えるかわからないので丸々クリップさせてもらおう…。
googleキャッシュがいつ消えるかわからないので丸々クリップさせてもらおう…。
904 :903:2007/08/12(日) 04:42:27
サーバーサイドにあるPHPにアクセスして、
ネットワークごしに画像をダウンロードする方法で戸惑っています。
// PHP側
<?php
$img = imagecraetefromgif("test.gif");
header("Content-Type: image/gif");
imagegif($img);
?>
// Java側
void downloadImage(String url) {
try {
HttpConnection hc
= (HttpConnection)Connector.open(path, Connector.READ, true);
hc.setRequestMethod(HttpConnection.GET);
hc.connect();
InputStream in = hc.openInputStream();
byte[] data = new byte[(int)hc.getLength()];
in.read(data);
...
}
このような関数で、引数urlでphpのスクリプトにアクセスして画像をダウンロードしたいと思っているのですが、
これだとhc.getLength()が-1で、明らかに正常にアクセスできていません。
ちなみに、urlでgif画像の直リンクを張った場合は正常に動作します。
PHPの出力方法に問題がありそうな気がするので若干スレ違い気味ですが、原因がわかる方がいましたらお願いします。
905 :デフォルトの名無しさん:2007/08/12(日) 07:00:26
> 原因がわかる方がいましたらお願いします。
ヘッダーにコンテントレングスをセットしていないから。
906 :デフォルトの名無しさん:2007/08/12(日) 07:13:22
Content-Lengthの出力はサーバ側の設定によるもの。
アパッチのコンフィグで設定するなり何なり。
一方、iアプリ側はgetLength()が-1になることも考慮した組み方をしておく。
Content-Lengthを設定しておらず、自分でもいじれないサーバではアプリ側で対処するしかない。
if ((int)hc.getLength() == -1){〜} else{〜} てな記述。
具体的な記述内容はググればいくらでも例が見付かる。
907 :デフォルトの名無しさん:2007/08/12(日) 10:43:49
>>904
>これだとhc.getLength()が-1で、明らかに正常にアクセスできていません。
getLength() が -1 でも正常にアクセスできててデータの中身はちゃんと読める。
908 :904:2007/08/12(日) 12:06:52
>>905
PHP側でContent-Typeを出力する前に
header("Content-Length : " . filesize("test.gif"));
を追加してみたのですが、connect()の段階で止まってしまうのです。
>>906-907
-1でも正常にアクセスできているのは、初耳でした。
確かにレスポンスコードは200だったのですが・・・、ありがとうございます。
以下のコードで、正常に動作することを確認しました。
// Java側 hc.openInputStream()以下
...
byte[] data;
if ((int)hc.getLength() != -1) {
data = new byte[(int)hc.getLength()];
in.read(data);
}
else {
ByteArrayOutputStream bs = new ByteArrayOutputStream();
while (true) {
int temp = in.read();
if (temp == -1) {
break;
}
bs.write(temp);
}
data = bs.toByteArray();
}
...
909 :デフォルトの名無しさん:2007/08/12(日) 12:17:17
公式資料に書いてあるっての
910 :デフォルトの名無しさん:2007/08/12(日) 14:17:20
>908
そして第2のはまりポイント
in.read(data); は一度で全部読み込めるとは限らないから
-1が返るまでループ処理してバッファに追記していくこと
911 :デフォルトの名無しさん:2007/08/12(日) 14:17:53
ってゴメン
それはちゃんと書いてあるね
912 :デフォルトの名無しさん:2007/08/12(日) 14:25:07
いや、getLength() != -1 のほうの
data = new byte[(int)hc.getLength()];
in.read(data);
これは良くない
↓のようにするか
data = new byte[(int)hc.getLength()];
int i = 0, n;
while ((n = in.read(data, i, data.length - i)) >= 0) {
i += n;
}
面倒かったら↓で
data = new byte[(int)hc.getLength()];
new DataInputStream(in).readFully(data);
913 :デフォルトの名無しさん:2007/08/12(日) 14:52:40
>>908
>connect()の段階で止まってしまうのです。
こりゃ実際に出力しているデータサイズが違うんじゃないの?
たとえば
ContentLength: 100を設定しておいて、データは90バイトしか送ってないとしたら
携帯側は残り10バイトが届くまで受信待ちの状態になってるだろうさ
914 :デフォルトの名無しさん:2007/08/12(日) 17:59:27
だな。鯖側の処理おかしいもん。
こんなんでどうよ?
<?php
$fname = "test.gif";
$fdata = file_get_contents($name);
$fsize = strlen($fdata);
header("Content-Length: ". $fsize );
echo $fdata;
?>
915 :914:2007/08/12(日) 18:04:08
あー、ちなみに何がおかしかったかというとimagecraetefromgif()でイメージリソース
として取得したデータを、PHPで出力時にGIFに再変換しているから元のデータと微妙に
変わっているということ(画像としては同じになるけどヘッダとか違う)。
で、出力サイズは元ファイルのを出しているから、正しいサイズになってない。
そもそもgd呼ぶような面倒なことはしないで、そのままバイナリ吐いてやればよかった。
916 :914:2007/08/12(日) 18:05:49
ごめ。2行目の引数は「$fname」な。
- $fdata = file_get_contents($name);
+ $fdata = file_get_contents($fname);
917 :904:2007/08/12(日) 21:18:41
>>912
ネット上で調べた文献の多くがこの方法だったので・・・、迂闊でした。
一回のread()で読み切れない場合があるってことですかね?
今ひとつ理解できていませんが、直しておきます。
>>913-916
この方法を使ったら、普通にgetLength()で取得できるようになりました。
file_get_contents()でリソースを取得すれば良かったのですね。
ありがとうございます、おかげ様で理想通りに動作するようになりました。
918 :デフォルトの名無しさん:2007/08/12(日) 21:24:49
>>917
InputStream#read は 「1バイト以上読む」 っていう仕様なので。
1バイトでも読めたらそれで返ってくることが許されてる
[ ツッコむ ]
以上です。