リクエストがAjax由来かそれ以外かを識別して、制御をかけたい時ありますよね。
- セキュリティ上、Ajaxリクエストの場合は排他したい
- Webアクセスしてほしくないから、Ajaxリクエストのみを許可したい
Symfonyでは、このような要件を簡単に実現できるよう、Requestオブジェクトが組み込まれています。
今回はAjaxリクエストの識別方法を紹介します。
もちろんデモを用意してきました。
Request
について
HTTPリクエストに関する情報を保持しているオブジェクトです。
Cookie操作やパラメータ操作など、扱えるデータがめちゃくちゃ多いです。
今回の、Ajax制御で利用するHeader情報等ももちろん操作することができます。
AJAXリクエストの識別方法
isXmlHttpRequest()
メソッドが用意されているのでそちらを活用します。
use Symfony\Component\HttpFoundation\Request;
public function myControllerFunction(Request $request)
{
if ($request->isXmlHttpRequest()) {
// AJAXリクエストに対する処理
} else {
// それ以外のリクエストに対する処理
}
}
こんな感じで結構シンプルですね。
中の実装までの細かい説明は省きますが、リクエストヘッダーに X-Requested-With: XMLHttpRequest
が含まれているかどうかをチェックする感じっぽいです。
実装例
LaravelとDrupalでの実装例を紹介します。
Drupalだったら…。
Routing
{module}/{module}.routing.yml
api.only_ajax:
path: "/api/only_ajax"
defaults:
_controller: "\\Drupal\\custom_api\\Controller\\Calendar::onlyAjax"
api.exclude:
path: "/api/exclude_ajax"
defaults:
_controller: "\\Drupal\\custom_api\\Controller\\Calendar::excludeAjax"
Controller
{module}/src/Controller/ApiController.php
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class ApiController extends ControllerBase {
/**
* Ajax通信のみ許可する.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function onlyAjax(Request $request) {
// Initialized.
$res = new JsonResponse();
if ($request->isXmlHttpRequest()) {
return $res->setJson(json_encode(['message' => 'Please Ajax!!']));
}
$products = [
['id' => 1, 'name' => 'Product 1', 'price' => 100],
['id' => 2, 'name' => 'Product 2', 'price' => 150],
];
return $res->setJson(json_encode($products));
}
/**
* Ajax通信以外を許可する.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function excludeAjax(Request $request) {
// Initialized.
$res = new JsonResponse();
if (!$request->isXmlHttpRequest()) {
return $res->setJson(json_encode(['message' => 'No Ajax!!']));
}
$products = [
['id' => 1, 'name' => 'Product 1', 'price' => 100],
['id' => 2, 'name' => 'Product 2', 'price' => 150],
];
return $res->setJson(json_encode($products));
}
}
Laravelだったら…。
Routing
routes/web.php
Route::get('/api/only_ajax', [ApiController::class, 'onlyAjax'])->name('api.only_ajax');
Route::get('/api/exclude_ajax', [ApiController::class, 'excludeAjax'])->name('api.exclude_ajax');
Controller
app/Http/Controllers/ApiController.php
class ApiController extends Controller
{
/**
* Ajax通信のみ許可する.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function onlyAjax(Request $request)
{
// Initialized.
$res = new JsonResponse();
if ($request->ajax()) {
return $res->setJson(json_encode(['message' => 'Please Ajax!!']));
}
$products = [
['id' => 1, 'name' => 'Product 1', 'price' => 100],
['id' => 2, 'name' => 'Product 2', 'price' => 150],
];
return $res->setJson(json_encode($products));
}
/**
* Ajax通信以外を許可する.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function excludeAjax(Request $request)
{
// Initialized.
$res = new JsonResponse();
if ($request->ajax()) {
return $res->setJson(json_encode(['message' => 'No Ajax!!']));
}
$products = [
['id' => 1, 'name' => 'Product 1', 'price' => 100],
['id' => 2, 'name' => 'Product 2', 'price' => 150],
];
return $res->setJson(json_encode($products));
}
}
※ Laravelは標準のRequestオブジェクトを拡張して、ajax
メソッドが用意されているようです。便利 🎉
Laravelの$request→ajax()
について
ここで実装されているようです。
Illuminate/Http/Request.php
/**
* Determine if the request is the result of an AJAX call.
*
* @return bool
*/
public function ajax()
{
return $this->isXmlHttpRequest();
}
他にも、かなり便利なメソッドが用意されているようです。ぜひのぞいてみてください。
Drupalにも標準でほしい。(あるのかな?)