今日のウェブ主導の世界では、サーバーは圧倒的な数のリクエストを処理する。これらのリクエストを効率的に分析し、カウントし、解釈し、再ルーティングすることは、特にMVCの原則を適用する場合に不可欠です。
4D HTTPサーバーの HTTPリクエストハンドラの導入により、受け取ったリクエストに基づいて特定のビジネスロジックをトリガーすることができます。この強力な機能により、多くの可能性が開けます。
HTTPリクエストハンドラを使えば、特定のURLパターンやHTTP動詞に合わせたハンドラを必要なだけ定義できます。このアプローチでは、従来の On Web Authentication や On Web Connection データベースメソッドよりもはるかに細かい設定が可能で、Case of ステートメントを実装する手間が省けます。
なぜリクエストハンドラを使うのですか?
リクエストハンドラを扱うと、次のようなさまざまなシナリオが生まれます:
- 指定した URL をリソースプロバイダとして使う(たとえば、特定の URL をコールしてさまざまなファイルをダウンロードする)
- 与えられたURLをファイルアップロードボックスとして使う(例えば、特定のURLを呼び出して様々なファイルをアップロードする)
- ビジネスコンテキスト(例えば、ユーザーが認証されたかどうか、ページが見つからない、権限が付与されたかどうか…など)に応じて、特定のページでリダイレクトを処理する。
- 受け取ったリクエストに関連する統計や情報を保持する。
- oAuth 2.0による認証の処理
HTTPリクエストハンドラの設定方法
HTTPリクエスト・ハンドラは、Project/Sourcesフォルダ内のHTTPHandlers.jsonファイルにセットアップする必要があります。
このファイルには、JSON形式のオブジェクト・コレクションが含まれています。各オブジェクトは、以下の情報を持つリクエスト・ハンドラを参照します:
- 処理するURLパターン
- URLで使用される動詞
- リクエストハンドラーコードが実装されている[シングルトンクラス+関数
例
HTTPHandlers.jsonファイル:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
質問です:これはどういう意味ですか?
答えこれは、GET または POST動詞で/start/で始まるリクエストがサーバーで受信されると、シングルトンGeneralHandling の関数gettingStarted が実行されることを意味します。
リクエストハンドラの実装方法
上記のシングルトンクラスは 共有されなければならない。
入力:新しい4D.IncomingMessageクラスのインスタンス
リクエストは、新しい4D.IncomingMessage クラスのオブジェクトインスタンスとしてサーバーで受信される。
以下の情報が利用可能です:
- リクエストの完全なURL
- urlの部分
- リクエストの動詞
- リクエストのヘッダ
- URL に入れられたパラメータ (もしあれば)
- リクエストの本文(もしあれば)
そして、リクエストハンドラはこれらの情報を使って、適切なビジネスロジックをトリガーすることができます。
出力: 4D.OutgoingMessageクラスのインスタンス
必要に応じて、リクエストハンドラは 4D.OutgoingMessageクラスのオブジェクトインスタンスを返すことができます。 すなわち、ブラウザが処理できる完全なウェブコンテンツ(ファイルコンテンツなど)です。
簡単な例
上記と同じHTTPHandlers.jsonファイルを使用します:
[
{
"class": "GeneralHandling",
"method": "gettingStarted",
"pattern": "start",
"verbs": "get, post"
}
]
リクエスト http://127.0.0.1/start/example?param=demo&name=4Dはブラウザで GET 動詞で実行されます。このリクエストは、以下のGeneralHandling シングルトン・クラスのgettingStarted() 関数によって処理される:
return $resultshared singleton Class constructor()
Function gettingStarted($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $body : Text
$body:="Called URL: "+$request.url+"\n"
$body+="The parameters are received as an object:"+"\n"+JSON Stringify($request.urlQuery; *)+"\n"
$body+="The verb is: "+$request.verb+"\n"
$body+="There are "+String($request.urlPath.length)+" url parts - Url parts are: "+$request.urlPath.join(" - ")+"\n"+"\n"
$result.setBody($body)
$result.setHeader("Content-Type"; "text/plain")
return $result
リクエストは、サーバー上で$request(新しい4D.IncomingMessage クラスのオブジェクト・インスタンス)として受け取られる。
この$requestオブジェクトはプロパティを含む:
- url (String) – リクエストのURL
- urlQuery (Object) – リクエストのパラメータ。
- verb (String) – 動詞。
- urlPath (文字列のコレクション) – リクエストのURL部分
これがレスポンスです:
リクエストのボディを処理する方法
新しい4D.IncomingMessage クラスは、リクエストの ヘッダーと ボディを 取得するための関数を提供します。
例
サーバー上にファイルをアップロードする簡単な例を実行してみましょう。
HTTPHandlers.jsonファイル:
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]
URL パターンはregexPatternプロパティで正規表現として与えられることに注意してください。
リクエスト http://127.0.0.1:8044/putFile?fileName=testFileは POST 動詞で実行され、ボディにファイルのコンテンツがあります。
UploadFile シングルトン・クラス:
Function uploadFile($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $response:=4D.OutgoingMessage.new()
var $body:="Not supported file"
var $fileName; $fileType : Text
var $file : 4D.File
var $picture : Picture
var $created : Boolean
//The file name is given as parameter in the URL
$fileName:=$request.urlQuery.fileName
// The header "Content-Type" provides the format of the body
$fileType:=$request.getHeader("Content-Type")
Case of
// The body contains a pdf file
: ($fileType="application/pdf")
$file:=File("/PACKAGE/Files/"+$fileName+".pdf")
$created:=$file.create()
// The getBlob() function returns the body of the request as a Blob
$file.setContent($request.getBlob())
$body:="Upload OK - File size: "+String($file.size)
// The body contains a jpg image
: ($fileType="image/jpeg")
$file:=File("/PACKAGE/Files/"+$fileName+".jpg")
// The getPicture() function returns the body of the request as a Picture
$picture:=$request.getPicture()
WRITE PICTURE FILE($file.platformPath; $picture)
$body:="Upload OK - Image size: "+String($file.size)
End case
$response.setBody($body)
$response.setHeader("Content-Type"; "TEXT/plain")
return $response
ファイル名はURLのパラメータ(fileName)として与えられる。これはリクエストのurlQuery オブジェクトで受け取られます。
リクエストのヘッダーとボディを取得する関数
上の例では、リクエストの指定されたヘッダーを返すgetHeader() 関数に注目してください。4D.IncomingMessage クラスは、すべてのリクエストヘッダを含むheaders プロパティ (Object) も提供します。
ヘッダContent-Typeは、受け取ったボディのフォーマットを提供します。この例では、pdfと jpegフォーマットだけが扱われます。
リクエストオブジェクトのgetBlob() とgetPicture() 関数に注目してください。これらは、Content-Typeヘッダにマッチする適切なフォーマットでボディの内容を提供します。
これらの関数の詳細については、ドキュメントを参照してください。
getText() 関数も使用可能で、リクエストのボディを文字列として提供します (文字列として送信された場合)。
ボディが有効なJSON表現として与えられた場合、 getJSON()関数は正しい型(例えば、Object, Collection, String, …)でその解決を提供します。
ハンドルのリダイレクト
リクエストハンドラは、4D.OutgoingMessage クラスのインスタンスを返すことで、特定のページにリダイレクトすることもできます。リダイレクトするページを示すためにLocationヘッダを使わなければなりません。
HTTP ステータス3xx は、 リクエストを完了させるためにクライアントが追加のアクションを取らなければならないことを示します 。
このシナリオを実行してみよう:
– ユーザーが認証されると、WebFolder/pages フォルダ内のすべてのhtmlページを表示できます。ユーザーが認証されていない限り、認証ページにリダイレクトされます。
– 要求されたページがこのフォルダにない場合、Not foundページが提供されます。
– ユーザーが/pagesフォルダのサブフォルダ内のページを要求した場合、Not authorizedページが提供されます。
HTTPHandlers.jsonファイル:
[
{
"class": "PagesHandling",
"method": "handle",
"regexPattern": "/pages/"
}
]
PagesHandling シングルトン・クラス:
shared singleton Class constructor()
Function handle($request : 4D.IncomingMessage) : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $file : 4D.File
//The user is not authenticated
If (Session.isGuest())
$result.setHeader("Location"; "/authentication/Authentication.html")
$result.setStatus(307)
Else
//The URL is an html page in the /pages folder
If (($request.urlPath.length=2) && (Position(".html"; $request.url)#0))
$file:=File("/PACKAGE/WebFolder"+$request.url)
//The pages exists
If ($file.exists)
$result.setBody($file.getContent())
$result.setHeader("Content-Type"; "text/html")
$result.setStatus(200)
//The pages does not exist
Else
$result.setHeader("Location"; "/error/NotFound.html")
$result.setStatus(307)
End if
//The URL is NOT a an html page in the /pages folder
Else
$result.setHeader("Location"; "/error/NotAuthorized.html")
$result.setStatus(307)
End if
End if
return $result
リクエストハンドラは、より複雑なビジネスロジックを可能にするSession オブジェクトにアクセスできることに注意してください(いくつかの特権の存在をチェックするには、Session.storage 共有オブジェクトを使用します)。
HDIをダウンロードしてHTTPリクエストの処理を練習し、クラスやその他の強力な機能を提案するプロジェクト・モードの世界に入るのをもう待つ必要はありません。