Code

2016年12月10日土曜日

Akamai Bad Request (400) Restful API Delete method

 TL; DR: If you don't have time to find the root cause, just change Delete method to Post.

 In the past several weeks, we were experiencing an issue with Akamai: in a special sequence like Get + Delete + Get, or Post + Delete + Post, the request after Delete returned a Bad Request with reference no (xxxx.xxx.0) from Akamai edge server. But it never happened in our own environment, even the prod evn behind Akamai.

 We had some meetings with Akamai support engineers. They suspected that there may be some function keeping the HTTP connection with their edge server. At first, they thought our endless scrolling function caused the issue. But in fact we just load more data at the first time, then render only the first part of the data in the screen. When user scroll, we load other parts.

 After they checked their log, they found browser is using the same TCP connection for our Delete request. Which happens in the following case:
   Get /favourites  => setting up a connect with content-length some number
   Delete /favourites/{id} => using the same connection, with content-length xxx
   Get /favourites => bad request (400) from Akamai

In this case, Akamai edge server is sending Keep-Alive header to browser, so browser may use the same TCP connection to send the Delete request => Akamai edge server counts Delete request content-length as something not correct => edge server is waiting for more data from the next request => so next Get doesn't count as a separate request, and because it doesn't match what edge server expects, edge just returns 400 bad request to browser.
(It happens as if something like nullPost, nullGet when content-length is not correct - by support engineers).

 Their explanation sounds reasonable, but I used Fiddler and Wire Shark to check the content-length for all the requests,  couldn't find any incorrect data. All numbers seemed to be correct.

 We didn't have enough time to look into this issue further, and thinking of the request after POST never fails, I changed our Restful API Delete method to Post. This fixed everything.

 I am still not sure where the problem is, but at least changing Delete to Post makes everything good...

 Hope in the future, I can get some chance to make this clear. :)

2016年11月12日土曜日

良い HTML を書こう

 最近 AEM 開発チームと一緒に仕事をしています。Front End に関してはみんな多少知っていますが、本物の Front End Dev ではないため、まぁ、結構な数の Front End Dev も Bad HTML を書いているようです。日々勉強しないと。
 さ、良い HTML ってなんでしょう?結構大きいテーマだから、とりあえず、自分の考えをリストしよう:
 ー HTML ページ全体的な構造がわかりやすく、無駄がないこと、すべての HTML Tag が正しく使われていること。例えば、<nav> や、<aside> などのタグ、とページ全体が上から、下へ、要素がロジックにあってるとか。
 ー Content First 主義。JavaScript 使ったり、CSS アニメーションを使ったり、ページは綺麗になりますが、Content はやはり第一です。ユーザーが JS を disable にすることもあるし、イメージをダウンロードしない設定もあるので、UK では 2% のユーザーがその部類らしいだそうです。(隣の Designer さんに聞いた話しです。)だから、JS などに拘らず、ページの Content はどこでも、どんなデバイスでもわかりやすく伝えられるならいいでしょう (Responsive は実は大変重要)。
 ー Accessibility は正しいこと。ページ全体の h1 や、h2 などが正しく、HTML タグに意味が正しく、どうしても HTML だけで難しい場合、ARIA 属性が正しいこと。HTML は実はそれほど動的ではないので、tab や、アコーディオンが Tag のみで難しいです。それで aria-hidden や aria-expand に使う必要ですね。
 ー ページ全体が Browser で軽くて、速いこと、いわゆるパフォーマンスが良いこと。100 ms 遅くなると、5% のユーザーを失うという記事がどこかで見たことがあるようです。具体的な数字は覚えてないけど。
CSS を <head> に、JS を <body> にロードするとか、minify とか、とにかくページを速くしないと。
 
 まぁ、ページのデザインなども重要ですが、HTML としては上記実現すれば、良い HTML だと思います。

 それでは。また後日何か思いついたら、追加します。

Pokemon Go にはまってる。。。

 Poke Index を完成するために、770 km 走った。

2016年10月16日日曜日

element.href と element.getAttribute('href') の区別

 先週、一つのバグを発見しました。まぁ、強いといえば、Back End の問題ですが、ただ引き起こされた原因は Front End にあります。
 まず、SSO をするとき、Return Url を Back End に渡していますが、もし相対 Url の場合、正しく動きますが、フルの Url を渡したら、途中で処理を止まりました。原因は Back End の処理は絶対 Url の処理はできていません。
 Domain は同じでも、Front End からどんな ReturnUrl 文字列が渡されるかはわからないので、ちゃんと処理しないと。。。

 この件、<a href="/digital/url"> を書きましたが、実際 Return Url を取得するとき、e.target.href を使ってしまいました。この場合、Browser は相対 Url に Base Url を自動的に追加します。そうすると、本来なら、相対パスであるところは絶対パスになってしまいます。。。
 解決方法は Back End 修正すべきですが、一応、 Front End も正しい動きにしたほうがいいと。e.target.getAttribute("href") にすれば、ちゃんと href 中の相対パスが取得できます。これは属性を直接使う場合、と getAttribute() 関数の違いです。
 ちなみに、jQuery はいつも getAttribute を使っているそうです。
 
 こちらは HTML Specification によると、.href を使う時は、DOM Property と呼んで、.getAttribute の場合は attribute となります。DOM Property は計算後の値になります。例えば、上記の .href。また .checked の場合、DOM Property なら true, false になりますた。.getAttribute を使うと、"" 空の文字列になる。今後ご注意を。

 それでは。

2016年10月3日月曜日

iOS での position: fixed をスムーズにする

 先日リリースした Web App の Header を position: fixed にしました。PC では問題ないですが、iOS や Android など Tablet Webkit 系では、ちょっと変な動きをしました。実際指でスクロールすると、Header が一瞬消えて、そのあと画面がほぼ静止したとき、 fixed になります。これは多分 Tablet 自身のパフォーマンス問題で、解決方法を調べてました。
 ネットではいろいろ書き込みがあります。基本的に
     transform: translate3D(0, 0, 0) を使ったり、transform: translateZ(0) を親要素に追加して、強制的に Layer を作って、ハードウェアの加速を使います。
 追加してみたら、ほぼ解決するようになりました。ただ、Header に要素が多い場合、まだまだ不自然です。デザイナーを相談して、できるだけ Header にある要素を Tablet の場合、減らしました。。。

 さらに調べてみると、transform: translate3D(0, 0, 0) か translateZ(0) を使うと、Browser はその要素を一つの Layer として、イメージを作って、Video Card のメモリにアップロードします。そのあと、何かアニメーションが起きたら、CPU の時間ではなくて、Video カードを使って、画面を更新しています。これは速いはずです。
 注意点としては、むやみにいろんな Layer を作ると、逆にパフォーマンスに悪影響が発生します。本当に使ったほうがいい時、使うよという書き込みもいっぱいあります。

 もう一つの注意点としては、新しい Layer が作られたため、z-index と translateZ(0) が衝突する可能性があります。例えば、親の間に z-index を使って、画面上の上下位置を調整していますが、親レベルですので、translateZ(0) を使うと、その z-index が効かなくなる可能性があります。よくテストしましょう。
 もう一つ、これは Tablet など画面の大きいデバイスでは、画面の小さい mobile phone では、position fixed を使わない方がいいです。media query を使って、header を元の位置に戻しましょう。
 それでは。

2016年9月18日日曜日

最新 React.js にアップデート

 先週、つい React.js のバージョンを 0.12 から 15.3 にアップグレードしました。Component 自身の修正はそんなに多くないですが、jest でのテストはかなり変わりましたので、少し時間がかかりました。
 まず、全ての node モジュールを最新バージョンにして、npm dedupe コマンドを実行して、node_modules のフォルダ構造をできるだけフラットにしました。これで、Windows でのファイル名が長すぎという git clone 時のエラーが少なくなるはずです。
 そのあと、Webpack の Config を修正して、transpile できるようにします。こちらは主に、loader の変更です。新しい Babel では、stage や、destructuring などの ES2015 フェーチャーを個々のモジュールに分けたので、preset に ES2015とReactを設定しなければなりません。こちらは .babelrc に追加します。jest も Babel loader を使うので、rc ファイルに設定したほうがいいです。そのあと、使っている ES2015 のフェーチャーを plugin に追加します。主に、destructuring になります。
 これで、transpile は通るようになります。ブラウザーで Web App をロードすると、いろんなエラーが出てきます。
 − App を DOM に render するとき、ReactDOM.render を使います。
 − getDOMNode() が削除されたので、ReactDOM.findDOMNode() に変更する必要があります。こちらは native の DOM Node div などを ref を入れると、自動的に DOM node の reference になるので、これはかなり便利になります。
 − props は完全に readonly になるので、過去の悪いコードを直しないといけません。
 − DOM node にサポートしない属性もエラーになりますので、こちらを props などの object から取り出して、設定する必要があります。例えば、contentKey とか自分で過去使っていた prop などに対して、 {...props} を使うところを { contentKey, ...others } = this.props をして、{...others} のみ React Component に渡します。
 − React Component は owner が必要とかのエラーは複数の React.js バージョンが存在したからです。過去の Third Party lib 中の React.js バージョンをチェックした方がいいです。
 − PureRenderMixin や classSet などの lib は React.js から分離されたため、個別に require する必要があります。
 こちらのエラーを直すと、基本的に Web App は動きます。

 一番大変なのは jest での Unit Tests の修正です。 setProps や、getDOMNOde() などもう使えないので、一括で findDOMNode() に変更したりして、動かない場所や、エラーになるところを一つ、一つ直す必要があります。こちらはほぼ一週間かかりました。(全部 1022 個 Unit test case)。
 なお、airbnb から enzyme というライブラリーが出てきたので、こちらをこれから使う予定です。jest よりかなり使い易いです。
 まぁ、全体的に見ると、そんなに手間をかかることではないので、早めにアップデートしたほうがいいかもしれません。

 それでは。

2016年9月10日土曜日

Web, mobile App と Restful API

 最近、作ってるアプリは Restful API を採用されました。こちらは二つの Layer があります。Web Layer と App Layer。具体的に、App Layer はデータを保存したり、処理するだけです。Web Layer は実際の Web アプリやモバイルアプリにコミュニケーションします。
 この二層 Layer は一見的に必要ないと思われてるかもしれません。ただ、API を使うとき、Web アプリとモバイルアプリの間に要求が違うときがあります。この場合、Web layer でその違いをカバーできます。さらに、JSON フォーマットの Data Contract は Web Layer で固めて、App Layer  はほぼ自由に変更できるようになります。
 例えば、Web の場合、通常ログイン状態は保持できないし、セッションタイムアウトもあります。モバイルの場合、基本的にログイン状態にあります。それで、フリーに見れるコンテンツとログインで見れるコンテンツをコントロールする必要があります。ただ、一旦ログインすると、もう扱うデータが同じになります。これは Web Layer と App Layer を分ける理由の一つです。
 もう一つの理由としては、今 AWS や Azure などの Cloud プラットフォームが使い易くなります。App Layer は自分の会社に配置して、Web Layer はAWS などを使います。App Layer も他の内部のシステムにも利用できますし、データも基本的に自社にあるから、他の会社に保存して、漏れるとかの心配も少ないでしょう。
 
 Web Layer と App Layer の間も基本的に HTTP Restful API になっています。Web Layer はアプリとの JSON Data Contract を定義して、DTO などは基本的に変更しにくいです。その後ろに存在する App Layer との間がデータのやり取りですので、変更は頻繁にあるかもしれません。アプリのバージョンが複数サポート必要があるとき、さらに使い易いです。
 それでは。