HTTP is een staatloos protocol (in ieder geval tot en met HTTP 1.1), dus de client vraagt een bestand op, de server stuurt een respons en de verbinding wordt gesloten (u kunt keep-alive inschakelen zodat de verbinding niet onmiddellijk wordt gesloten, maar dat valt buiten het bestek van dit artikel). Sessies stellen u in staat informatie over de client op te slaan, die bijvoorbeeld kan worden gebruikt bij het inloggen van een client. U kunt een willekeurige unieke sessie-ID gebruiken, de lijst met sessies doorzoeken om te zien of er al een bestaat, en zo niet een nieuwe sessie aanmaken. Een sessie kan worden vernietigd na een periode van inactiviteit of handmatig na het uitloggen van de client.
Er zijn enkele eigenschappen in TsgcWebSocketHTTPServer die sessies in het servercomponent in- of uitschakelen. De belangrijkste zijn:
| Eigenschap | Beschrijving |
| SessionState | Dit is de eerste eigenschap die moet worden ingeschakeld om sessies te kunnen gebruiken. Zonder dat deze eigenschap is ingeschakeld, werken sessies niet |
|
SessionTimeout |
Hier moet u een waarde groter dan nul instellen (in milliseconden) voor de maximale tijd dat een sessie actief zal zijn. |
| AutoStartSession | Sessies kunnen automatisch worden aangemaakt (AutoStartSession = true) of handmatig (AutoStartSession = false). Als sessies automatisch worden aangemaakt, gebruikt de server RemoteIP als unieke identificator om te controleren of er een actieve sessie is opgeslagen. |
| SessionClass | Optioneel. De klasse die de server gebruikt wanneer hij een nieuwe sessie maakt. Stel deze in op uw eigen TIdHTTPSession-afstammeling om uw eigen gegevens in elke sessie op te slaan. Moet worden ingesteld voordat de server wordt geactiveerd. |
| SessionList | De lijst met de actieve sessies. Lees hem om sessies via code te zoeken, aan te maken of te verwijderen. U kunt ook uw eigen lijst toewijzen als u volledige controle nodig hebt over waar sessies worden opgeslagen. Moet worden toegewezen voordat de server wordt geactiveerd. |
TsgcWebSocketHTTPServer1.SessionState := True;
TsgcWebSocketHTTPServer1.SessionTimeout := 600000;
TsgcWebSocketHTTPServer1.AutoStartSession := False;
Om een nieuwe sessie te maken, moet u een nieuwe sessie-ID aanmaken die uniek is. U kunt elke gewenste waarde gebruiken. Voorbeeld: als de client zich authenticeert, kunt u gebruikersnaam + wachtwoord + extern IP-adres als sessie-ID gebruiken.
Zoek vervolgens in de sessielijst om te controleren of deze al bestaat. Als deze niet bestaat, maakt u een nieuwe aan.
Wanneer een nieuwe sessie wordt aangemaakt, wordt de gebeurtenis OnSessionStart aangeroepen en wanneer de sessie wordt gesloten, wordt de gebeurtenis OnSessionEnd geactiveerd.
procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
var
vID: String;
oSession: TIdHTTPSession;
begin
if ARequestInfo.Document = '/' then
AResponseInfo.ServeFile(AContext, 'yourpathhere\index.html')
else
begin
// check if user is valid
if not ((ARequestInfo.AuthUsername = 'user') and (ARequestInfo.AuthPassword = 'pass')) then
AResponseInfo.AuthRealm := 'Authenticate'
else
begin
// create a new session id with authentication data
vID := ARequestInfo.AuthUsername + '_' + ARequestInfo.AuthPassword + '_' + ARequestInfo.RemoteIP;
// search session
oSession := TsgcWebSocketHTTPServer1.SessionList.GetSession(vID, ARequestInfo.RemoteIP);
// create new session if not exists
if not Assigned(oSession) then
oSession := TsgcWebSocketHTTPServer1.SessionList.CreateSession(ARequestInfo.RemoteIP, vID);
AResponseInfo.ContentText := '<html><head></head><body>Authenticated</body></html>';
AResponseInfo.ResponseNo := 200;
end;
end;
end;
Zodra een sessie bestaat, koppelt de server deze aan elk verzoek dat de sessiecookie draagt. Lees deze uit ARequestInfo.Session, die nil is wanneer het verzoek geen sessie heeft.
procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
begin
if Assigned(ARequestInfo.Session) then
begin
// Content is a TStrings you can use to store your own values
ARequestInfo.Session.Content.Values['visits'] :=
IntToStr(StrToIntDef(ARequestInfo.Session.Content.Values['visits'], 0) + 1);
AResponseInfo.ContentText := 'Session ' + ARequestInfo.Session.SessionID +
' visits: ' + ARequestInfo.Session.Content.Values['visits'];
end
else
AResponseInfo.ContentText := 'No session';
end;
Als u uw eigen velden in elke sessie wilt bewaren, in plaats van de Content-stringlijst te gebruiken, maak dan een afstammeling van TIdHTTPSession en laat de server die gebruiken via de eigenschap SessionClass. Stel deze in voordat de server wordt geactiveerd.
De server blijft voor al het overige zorgen: hij genereert het unieke sessie-ID, verstuurt de sessiecookie, past SessionTimeout toe en verwijdert verlopen sessies. Overschrijf de virtuele constructor CreateInitialized als u eigen velden wilt initialiseren wanneer de sessie wordt aangemaakt.
type
TMySession = class(TIdHTTPSession)
private
FUserName: String;
FLoginTime: TDateTime;
public
constructor CreateInitialized(AOwner: TIdHTTPCustomSessionList;
const SessionID, RemoteIP: string); override;
property UserName: String read FUserName write FUserName;
property LoginTime: TDateTime read FLoginTime write FLoginTime;
end;
constructor TMySession.CreateInitialized(AOwner: TIdHTTPCustomSessionList;
const SessionID, RemoteIP: string);
begin
inherited CreateInitialized(AOwner, SessionID, RemoteIP);
FLoginTime := Now;
end;
// configure the server before it starts
TsgcWebSocketHTTPServer1.SessionState := True;
TsgcWebSocketHTTPServer1.SessionTimeout := 600000;
TsgcWebSocketHTTPServer1.SessionClass := TMySession;
TsgcWebSocketHTTPServer1.Active := True;
// and read it back in any request
procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
begin
if ARequestInfo.Session is TMySession then
AResponseInfo.ContentText := TMySession(ARequestInfo.Session).UserName;
end;
Als u volledige controle nodig heeft over hoe sessies worden opgeslagen, bijvoorbeeld door ze in een database te bewaren of tussen meerdere servers te delen, wijs dan vóór activering van de server uw eigen lijst toe aan de eigenschap SessionList. Erf over van TIdHTTPDefaultSessionList en override de virtuele methode CreateSession. De server roept deze intern aan vanuit CreateUniqueSession, zodat de unieke sessie-ID nog steeds voor u wordt gegenereerd.
Wanneer u uw eigen SessionList toewijst, is de eigenschap SessionClass niet langer van toepassing, omdat uw lijst bepaalt welke klasse wordt aangemaakt.
type
TMySessionList = class(TIdHTTPDefaultSessionList)
public
function CreateSession(const RemoteIP, SessionID: string)
: TIdHTTPSession; override;
end;
function TMySessionList.CreateSession(const RemoteIP, SessionID: string)
: TIdHTTPSession;
begin
Result := TMySession.CreateInitialized(Self, SessionID, RemoteIP);
SessionList.Add(Result);
end;
// assign it before the server starts
TsgcWebSocketHTTPServer1.SessionList := TMySessionList.Create(nil);
TsgcWebSocketHTTPServer1.Active := True;
Met de gebeurtenis OnCreateSession kunt u zelf een sessie-instantie teruggeven, maar er wordt geen sessie-ID aan toegekend. Als u de sessie met een gewone constructor maakt, zijn de sessie-ID en de sessiecookie leeg en kan de sessie bij het volgende verzoek nooit meer worden teruggevonden. Gebruik in plaats daarvan SessionClass, dat eenvoudiger is en dat allemaal voor u afhandelt.
Roep ook SessionList.CreateUniqueSession niet aan binnen OnCreateSession. Die methode voegt de nieuwe sessie al toe aan de lijst, en de server voegt deze opnieuw toe wanneer uw handler terugkeert, zodat dezelfde sessie tweemaal in de lijst terechtkomt.