W międzyczasie myślałem o obsłudze sesji i zmianie jej ID - w sytujacji, gdy wykonujemy asynchroniczne (a szczególnie liczne) zapytania do serwera HTTP nie jest to dobry pomysł. Dlaczego? Ogólnie o tym na poniższych diagramach. Szczegółowo może w przyszłym artykule.
Przykłady diagramów
Standardowe żądanie i przepływ danych w skrypcie PHP
Standardowo wszystko wykonuje się szeregowo. Nie ma więc miejsca na jakiś brak synchronizacji.Kod:
(start)->(user clicks)
(user clicks)->(request)
(request)->(send sess id)
(send sess id)->(start session)
(start session)->(regenerate id)
(regenerate id)->(send back new sess id)
(send back new sess id)->(continue app)
(continue app)->(respond)
(respond)->(end)
(user clicks)->(request)
(request)->(send sess id)
(send sess id)->(start session)
(start session)->(regenerate id)
(regenerate id)->(send back new sess id)
(send back new sess id)->(continue app)
(continue app)->(respond)
(respond)->(end)
Diagram:
Problem przy zapytaniach asynchronicznych
W przypadku zapytań asynchronicznych możemy natrafić na sytuację, gdy SESSION ID zmieni się na serwerze, ale nie zdąży się zaktualizować na kliencie - czego wynikiem będzie wysłanie żądania w ramach nieistniejącej sesji.Kod:
(start)->(user clicks)
(user clicks)->|z|
|z|->(request A)
(request A)->(send sess id A - 1)
(send sess id A - 1)->(start session with A - 1)
(start session with A - 1)->(regenerate id)
(regenerate id)->|a|
|a|->|b|
|b|->(send back new sess id B)
(send back new sess id B)->(end)
|z|->(user reads page)
(user reads page)->(user clicks again)
(user clicks again)->(request B)
(request B)->(send sess id A - 2)
(send sess id A - 2)->|a|
|a|->(start session with A - 2 - no session!)
(start session with A - 2 - no session!)->|b|
|b|->(regenerate id again)
(regenerate id again)->(send back new sess id C)
(send back new sess id C)->(end)
(user clicks)->|z|
|z|->(request A)
(request A)->(send sess id A - 1)
(send sess id A - 1)->(start session with A - 1)
(start session with A - 1)->(regenerate id)
(regenerate id)->|a|
|a|->|b|
|b|->(send back new sess id B)
(send back new sess id B)->(end)
|z|->(user reads page)
(user reads page)->(user clicks again)
(user clicks again)->(request B)
(request B)->(send sess id A - 2)
(send sess id A - 2)->|a|
|a|->(start session with A - 2 - no session!)
(start session with A - 2 - no session!)->|b|
|b|->(regenerate id again)
(regenerate id again)->(send back new sess id C)
(send back new sess id C)->(end)
Diagram:
Inny przykład na desynchronizację
Oto co może dziać się po stronie serwera i klienta.Kod:
(start)->(1:request, id=A)
(1:request, id=A)->(2:request, id=A)
(2:request, id=A)->(1:start session, id=A)
(1:start session, id=A)->(1:regenrate id, new id=B)
1:regenrate id, new id=B)->(2:start session, id=A)
(2:start session, id=A)->(1:do sthing)
(1:do sthing)->(2:regenrate id, new id=B)
2:regenrate id, new id=C)->(2:send id back, id=C)
(2:send id back, id=C)->(client: gets new id=C)
(client: gets new id=C)->(1:send id back, id=B)
(1:send id back, id=B)->(client: gets new id=B)
(client: gets new id=B)->(2:do sthing with no session)
(2:do sthing with no session)->(client: do sth with bad id, id=B, id on server=C)
(client: do sth with bad id, id=B, id on server=C)->(end)
(1:request, id=A)->(2:request, id=A)
(2:request, id=A)->(1:start session, id=A)
(1:start session, id=A)->(1:regenrate id, new id=B)
1:regenrate id, new id=B)->(2:start session, id=A)
(2:start session, id=A)->(1:do sthing)
(1:do sthing)->(2:regenrate id, new id=B)
2:regenrate id, new id=C)->(2:send id back, id=C)
(2:send id back, id=C)->(client: gets new id=C)
(client: gets new id=C)->(1:send id back, id=B)
(1:send id back, id=B)->(client: gets new id=B)
(client: gets new id=B)->(2:do sthing with no session)
(2:do sthing with no session)->(client: do sth with bad id, id=B, id on server=C)
(client: do sth with bad id, id=B, id on server=C)->(end)