弊社インフォマートではサービス開発時、WebアプリケーションフレームワークとしてWicketを使用しています。
ほとんどのサービスが会員向けですが、一部外部公開しているサービスがあり、外部公開時にいくつか注意点があることが分かりました。
この文書には、Wicketを外部公開する際に気を付けるべき注意点を記載します。
まとめ
- Wicketで作ったアプリケーションを外部公開する場合の注意点がいくつかあり、そのポイントを気にしないと作り手側、ユーザー側が予期しない結果となる。
- 外部公開するページには、canonicalタグを付与して、正規のURLを検索エンジンのボットに認識させる。
- リンクはBookmarkableLinkを使用する。
- 不要なリダイレクトはRenderStrategyの変更で対応できる。
- Formは一時的なURLのほうがセキュリティ的に都合が良い。FormのURLはrobots.txtでdisalowを設定する。
- 外部公開前提の場合は、Statelessなページになるようなコーディングを心掛ける。
そもそもWicketとは?
Apache Wicket - Wikipedia を引用します。
Apache Wicket(アパッチ・ウィケット)は、Apacheソフトウェア財団のApache Wicketプロジェクトにて開発されているオープンソースのJava Webアプリケーションフレームワークである。
コンポーネント指向のWebフレームワークで、似たような設計思想のフレームワークとして以下があります。
- JSF
- Vaadin
- Tapestry
Genericな解説は他の記事や、公式ドキュメントに記載があるのでここではとくに言及しませんが、個人的には以下のような感想を持っています。
- Androidと似ている。どちらもSwingの設計思想をベースにしている。
- Spring 、Struts等のアクションベースのフレームワークを触った後だと、フレームワークの挙動の意味を理解するのに時間がかかる。
- Reactとコンポーネントの考え方は変わらないので、WicketからReactに行くのはそこまで違和感ない気がする。
動作確認に使用したWicketのVersionについて
WicketはVersionごとで公開APIのIFに結構な差異があります。
動作確認には、以下のVersionのWicketを使用しました。
<!-- https://mvnrepository.com/artifact/org.apache.wicket/wicket-core -->
<dependency>
<groupId>org.apache.wicket</groupId>
<artifactId>wicket-core</artifactId>
<version>1.5.5</version>
</dependency>
Wicket の Version が 1.4x - 1.5x
は当文書で記載の動作をするかと思いますが、最新Versionでは動作が異なる可能性があります。
別途動作確認をすることをお勧めします。
Wicketを外部公開する上で意識すべき前提動作
以下、Wicketで作成したWebアプリケーションを外部公開するうえで意識すべき前提動作について記載します。
デフォルト動作だとページ表示時にリダイレクトが走る。
Wicketはブラウザからのリクエストを受け取ると、デフォルト動作で以下のような挙動をします。
- リクエストURLに対応したPageクラスをインスタンス化し、メモリ上に格納する。
- リクエストURLにVersion番号を付与し、ブラウザにHTTPコード
302
でリダイレクトさせる。 - ブラウザがVersion番号付きURLにアクセスすると、メモリ上に格納したPageクラスを取り出しHTTPコード
200
でブラウザ描画したHTMLを返す。
この挙動により、Wicketの生成するFormのURL、aタグのURLは一時的なURLとなり、CSRF対策にもなります。
しかしながら、この動作が、SEO対策としては ✘
で、以下のような問題が発生します。
- Google Search Consoleでは不要なリダイレクトを繰り返しているページがあると検知される。
- Google Adsense設置ページでは不要なリダイレクトをしていると検知される。
また、1度リダイレクトするということは、DNS Lookupが多く走ることになり、ページパフォーマンス観点でも ✘
かなと思われます。[^1]
[^1]リダイレクト後のアクセスは、メモリCacheに乗っている扱いになるので、レスポンスタイムの問題になることはありません。
Referrence Guideにも、この挙動についての記載があります。
Wicket 8.x Reference Guide
デフォルト動作は REDIRECT_TO_BUFFER
と呼ばれ、これ以外に他2種類モードがあります。
Referrence Guideには、それぞれのモードのメリット、デメリットが記載されています。
URLのバージョン番号
デフォルト動作 だと ページ表示時にリダイレクトが走る
に記載しましたが、302
のリダイレクト時に、?134
のようなバージョン番号がURLに付与されます。
検索エンジンは基本的にパラメーター付きページを、別々ページであると認識します。
実際のところは、上手くやってくれるのかもしれませんが、検索結果として悪影響がある可能性もあります。
Link、FormのURLの問題
WicketでBookmarkableではないLink、Formを使用すると、以下のようなURLが生成されます。
これはブラウザ単位に割り当てられる一時的なURLとなり、セキュリティ対策としては◯
ですが、検索エンジンのボットのアクセスの場合、検索エンジンがこの一時的なURLをCacheしてしまいます。
- Form
<form id="id2" method="post" action="./xxxxxxxxxxxxxx?0-2.IFormSubmitListener-headerPanel-resizePanel-formFont">
- Link
<a href="./xxxxxxxxxxxxxx?0-3.ILinkListener-headerPanel-loginPanel-loginMenu-liLog_in_1-linkLogin">
この結果、検索エンジンの検索結果には表示されるが、アクセスしても期待するページは表示されない状態になります。
注意点
気を付けるべきポイントは以下になります。
canonicalタグを付与する
?123
とURLに付与されるVersion番号に対する対策です。
canonicalタグというタグをhead内に記載すると、コンテンツの正規URLを検索エンジンに明示できます。
canonicalタグとは?設置方法やよくある間違いも解説!|アクセス解析ツール「AIアナリスト」ブログ
付与の仕方は、WicketのVersionにより異なりますが、Wicket 8 であれば、MetaDataHeaderItem#forLinkTag
を使用することで、付与可能です。
Wicket 8.x Reference Guide
リンクはBookmarkableLinkを使用する。
ページにLinkを追加する際、Linkではなく、BookmarkableLinkを使うと、@MountPath
で指定したURLをリンク文字列として使用できます。
- Pageクラスの
@MountPath
の指定例
@MountPath("/news/search/top.page")
public class NewsSearchTopPage extends Webpage {
- BookmarkablePageLinkの使用例
BookmarkablePageLink<NewsSearchTopPage> lnkTop = new BookmarkablePageLink<>("lnkTop", NewsSearchTopPage.class);
addOrReplace(lnkTop);
@MountPath
の使用方法は、Wicket-Stuff Annotation の使い方 - Qiita が参考になります。
RenderStrategyを変更して、リダイレクトが発生しないようにする
Wicketはデフォルトでページ表示時に必ずリダイレクトをする動作をしますが、RenderStrategy
を設定することでこの挙動を変更できます。
ONE_PASS_RENDER
にすると、リダイレクトせずページを表示する動作になることから、検索エンジン対策のために対象ページを決定し挙動を変更しました。
RenderStrategy
の指定は、基本的にWicketのApplicationクラスで行い、war単位でのコントロールになります。
弊社で実施したかったことは、一部のページのみのRenderStrategy
の変更でしたので、以下Stack OverflowのQAを参考に一部のページのみのRenderStrategy
を変更しました。
Is RenderStrategy.ONE_PASS_RENDER a reasonable way to get rid of page version parameters like ?1 in a Wicket application? - Stack Overflow
robots.txtでWicket生成する一時URLをdisalow設定する。
単純なサイト内リンク等は、BookmarkablePageLink
で検索エンジンに拾ってもらえばよいのですが、Submit時のURL等、一時リンクで問題URL、そもそも拾って欲しくないURLもあります。
これら検索結果に表示されなくてもよいURLについては、robots.txtで以下のようにdisallow指定をしました。
# disallow auto generate url in wicket
Disallow: /*IFormSubmitListener
Disallow: /*ILinkListener
Disallow: /*IBehaviorListener
そもそも、Statelessにできないか検討する
外部公開前提のサイトで、Wicketを使用する場合は、Statelessにできないか検討するのもよいかと思います。
Stalelessにすることができれば、バージョン管理のためのバージョン番号がURLに付与されることはなくなります。
Wicketで真のステートレスページ - argius note
ページがStatelessかどうかを確認するためのUtilityが提供されていますので、Stateless前提でコンポーネントを作る際は組み込んでもいいかもしれません。
wicket/wicket-devutils at master · apache/wicket
WicketのコミニティのSEOに対する認識
WicketのコミニティもSEOとの相性の悪さを認識しているものと思われます。
Better SEO for stateful pages
というアイデアが記載されています。
Ideas for Wicket 8.0 - Apache Wicket - Apache Software Foundation
今後のリリースで、SEOに良い影響を与えるがリリースされる可能性もあるので、バージョンアップ情報は定期的に見ていくのが良いかと思われます。