Socket.ioとIE、CoffeeScriptの?とIE、indexOfとIEなどにつまずく。
ども、2日連続でエントリしちゃうぜ!kaminalyです。
今日は、色々とハマったのでメモ。
Socket.ioを使った開発をCoffeeScriptで楽しく進めていた。
ChromeとFirefoxで検証して問題なかったが、
さすがIE、華麗に地獄を味合わせてくれた。
ガッデム!
※全部IEのせいにしたいけど本当は違う。
まずは軽いところから、
indexOfにまつわる話。
配列内を検索するのにindexOf使ったら、
IEに「そんなメソッドねーよバカ」と怒られました。
例えば、こんなの。
[code lang="js"] var list = ["hoge","fuga"]; if(list.indexOf("hoge") !== -1){ console.log("配列にhogeいるよねぇ〜"); } [/code]
AS3では使えたので、自然と使ってたんです。
しかも、ChromeとFirefoxのjs実行エンジンでは使えるのに!
調べたらIEの配列にはindexOfの実装がないと。。
indexOfを鬼のように使ってしまっていたら、
Arrayのprototypeを拡張すれば、この危機は切り抜けられます。
自分は2カ所だけだったので、jQuery.inArrayを使いました。
※この時、そういえば、jQueryに配列検索する関数あったなと思い出した。
※prototypeもArrayを拡張してindexOf追加してたなぁ。とさらに思い出す。
次に、CoffeeScriptの?について。
たとえば、CoffeeScriptでこんなふうに書くと、
[code lang="coffee"] console?.log? "hoge" [/code]
こんな感じに吐き出してくれる。
[code lang="js"] if (console != null) { if (typeof console.log === "function") { console.log("hoge"); } } [/code]
ん〜。とても便利。
がしかし、IEでは、window.closeとか、document.getElementByIdとか
ネイティブな関数をtypeofすると”object”を返すやつがいる。
だから、たとえば次の例だと30%の確率でwindowが開く。でも、閉じてくれない。
//追記
自分が定義した関数でも”object”を返すことがあることがわかりました。
自分が見つけたパターンは、親と子のウィンドウで、
親から子、子から親にアクセスして関数をtypeofすると”object”を返しました。
//////
[code lang="js"] var w; if(Math.random() < 0.3){ w = window.open("", "_blank"); }else if(Math.random() < 0.6){ w = {}; } if (w != null) { if (typeof w.close === "function") { w.close(); } } [/code]
まぁ、これは極端な例だけど、
実際につまづいた。
これは、Coffeeのバグというか、漏れなのかな。
対処方法があるかは謎だけど。そのうちFixされればいいなぁ。
と、ここまでは、ちょっとした修正で終わると思っていたんだ。
そう、ここまでは。。。
最後にSocket.ioとIE
ラスボスが待ってた。
いや、攻略方法がわかってれば楽勝だったんだけど、
これは、解決までかなり遠回りした。
2つのエラーを回避したあと、見慣れないエラーログを見たんだ。
ソケットポリシーファイルがないから君には通信させるわけにはいかないって
見知らぬflashが言っている。
どうやら、Socet.ioのクライアントがIEでのwebsocketの通信をあきらめたあと、
次に選択したのがflashのsocket接続だったようだ。
うんうん。その話は聞いたことがあるよ。
でも、ソケットポリシーファイルの話はしらないな。
調べてみると、flashでsocket接続する時は、
crossdmain.xmlみたいなxmlを用意しないといけないと。
しかも、843番ポートにアクセスするからよろしくねとか言ってる。
apacheとnode.jsは使ったから、
今度はpytonでサーバ立ててみるか。
pythonは入ってたから、pip入れて、必要なモジュールをインストール。
環境を整えると、まえにHello Worldしたときのコードをちょこちょこっと書き換えてアップした。
うんうん。843番ポートでアクセスすると、xml返してくるね。うんうん。
で、IEでチェック。
…
エラー。
さらに深く調べると、httpではなくてソケットで接続するからヨロ♪って書いてあった。
ちきしょー。
pythonでソケット接続のコード書き始めたけど、
perlのflashソケットポリシー用サーバのサンプルコードを見つけたので、
perlに乗り換える。
もう既に数時間経過していたから、ためらいはなかった。
perlのサーバ起動。
・・・
エラーは消えた?
がしかし動かない?
What’s マイケルお祭りかい?
と、ここで、node.jsのログに怪しい文字列!
warn transportsにflashsocketが見つからないぜベイベ。
なるほど、transportsとflashsocketは見覚えがあった。
Socket.ioの設定関連だな。
すぐに見つかった。
Socket.IO API 解説
このページのオプション設定という項目に答えがあった。
デフォルトでflashsocketはtransportsに含まれていないらしい。
じゃあ、なんでクライアントはflashsocket選んじゃうのさoTL
環境の切り替えとか必要ないし、Socket.ioのソース読んだら、
io.configureで設定しなくてもio.setでそのまま設定できそうだったから、
シンプルに下記を足した。
ちなみにCoffeeScriptです。
[code lang="coffee"] io.set 'transports', [ 'websocket' 'flashsocket' 'htmlfile' 'xhr-polling' 'jsonp-polling' ] [/code]
ついにIEでも動き出したぞ。
やたー!!
どうやら、flashsocketを設定すれば、
Socket.ioがflashソケットポリシーを吐いてくれるみたいなので、
pythonやperlの件は無意味だったんだよ。
マジ泣ける。