简体   繁体   中英

How to show online users with ajax

I'm want to show all the users that are online, in real-time on my website. Not sure how to go about this though. It can't be hard to add new users once they log in, but I'll also need to remove users that are not logged in anymore.

Any idea how to do this? Should I check with jQuery what users have loged off and remvove them from the list etc?

Your problem is going to be people navigating away without logging out, their session will still exist for how ever long you have the timeout set before their session data is subject to collection (actually possibly much longer)

To get a truly accurate count of who is logged in and visiting the site you will need each client to send a "heartbeat" to the server every few seconds or minutes. on each heartbeat trigger you would want to expire any users that have not checked in within the allotted time frame.

The heartbeat signal would probably best consist of the username and a timestamp at a minimum, but could include any information you want to track.

When a client sends a single to the server have it check for an existing record for that username and overwrite the timestamp information if a record already exists, otherwise add a new one. Afterwords drop any user entries that have not checked in. Probably best to have the signal happen more often than the expiration. like signal every 30 seconds and clean up every minute.

(Edited, changed my mind, better to do it all in the same sequence instead of separately) Then return the currently logged in users from your active table which would be as easy as a SELECT * FROM table since the table will always be clean.

Client Side:

Here is a light example of a client-side library to handle firing the heartbeat function and catching the results.

//Client-side parent variable declaration (simulated namespacing)
var Client = Client || {};
Client.Pulse = null; //Holds a pointer to the heartbeat timer (id)
/* If you needed to cancel the heartbeat processes you could
 * pass this variable to clearTimeout(). Calling Client.Heartbeat()
 * again would start the cycle back up.
 */

//Initial event that will kick off the chain when the DOM is ready
$(document).ready(function(){
  Client.Heartbeat(); //Initial call to the Heartbeat function
});//ready

/// Sends the heartbeat signal and retrieves the currently active user list
Client.Heartbeat = function(){
  var sUsername = 'SomeUser';
  /* Note: If you have an active session running on the server it would not be 
   * necessary to send the username since you could pull it on the backend 
   * script which would be more tamper-proof anyway. I'm just giving an
   * example of sending data to the server using the jQuery.ajax method
   * If you were storing the username to be sent from the client; this wouldn't 
   * be a good place to do it anyway
   * 
   * Remove the "data : {...}" line below to exclude sending information to the server
   * The "type : 'post'" line would not be necessary either 
   */

  $.ajax({ //Send the signal and recieve the information about active users back
    url : '/lib/server/Heartbeat.php',
    type : 'post',
    dataType : 'json',
    data : {Username : sUsername },
    success : function(jActiveUsers,sStatus,jqXHR){ 
      /* This is the callback function of the request, jActiveUsers will be the 
       * json object with the information you choose to send back to it
       */
      Client.RenderActiveUsers(jActiveUsers); //Call the display function
      //Trigger the next delayed call to Client.Heartbeat
      Client.Pulse = setTimeout(function(){
        Client.Heartbeat();
      },30000); //30 second delay before next trigger
    }//success
  });//$.ajax
}//Heartbeat

/// Processes the results sent by the server and draws them to the UI
Client.RenderActiveUsers = function(jActiveUsers){
  /* This is where you would get a handle whatever element(s) on the page
   * will be displaying the information about currently active users
   * and filling it with the list of users how ever you would wish to display it.
   */
}//RenderActiveUsers

Because you will be dealing with asynchronous callbacks setTimeout() calls at the end of a full cycle to start the process over again will be a cleaner way of handling the interval if you were to use setInterval() and the server took longer than expected to return you could see the client start to race on itself. Using a setTimeout() within a successful callback also allows you to fail gracefully in the event the server-side heartbeat processor stops working; so will the client side instead of continuing to make failed attempts (if you want it to keep trying you just need to add a retrigger on a failed response as well).

Server Side:

I apologize I am not familiar with Java as a back-end service, I will be making some assumptions based on how PHP works; so I cannot guarantee it will map directly to your environment. Database examples will assume MySQL. code examples will be pseudo-cody PHP(ish)

On the server end of it you will need a new table for tracking the active users. You will possibly already be tracking when they log in within the database but this would be separate from that system (though you could of course link to it to get extra user details for your return structure)

The table would look at a minimum something like:

 ActiveUsers
 -----------------------------------------
 |   Field    |    Type     | NULL | Key |
 -----------------------------------------
 | Id         | int         |      | PRI |
 | Username   | varchar(xx) |      |     |
 | LastPulse  | datetime    |      |     |
 | FirstPulse | datetime    |      |     |
 -----------------------------------------

(speculation) I'm assuming that like PHP there are Sessions in Java which you can use to store information about a particular visitor like their current status. In PHP this works by passing an identifier back and forth between the client and server, allowing the server to identify a particular client and for you on the back-end to store variables related to that session (For instance a boolean with the current login state of the user, or a string to hold their username once logged in.)

If this is available to you it would be a much more secure way to handle authentication than to store this information client-side and allow the client to indicate if and as who it is logged in. Herein assuming it is....

When the client sends the heartbeat to the server you can access their logged in state and username from the session variables if they are in-fact logged in to begin the process.

if($LoggedIn && ($Username != null)){ //Session information

If they are not logged in you would skip down to the list retrieval part since you won't need to add or modify a record for them

Check if they have a record in the active table

SELECT `Id` FROM `ActiveUsers` WHERE `Username` = '{$Username}' LIMIT 1

If a record exists it means they have already checked in before and you want to update the record with a new timestamp using the Id value returned from the first query

UPDATE `ActiveUsers` SET `LastPulse` = NOW() WHERE `Id` = {$Id}

If no record exists you will want to make a new one for this user instead

INSERT INTO `ActiveUsers` (`Username`,`LastPulse`,`FirstPulse`) VALUES ('{$Username}',NOW(),NOW()) 

Next comes the maintenance phase of the process where you clean up any entries that have not checked in with in the amount of time you want to set as the limit (2 minutes in this example)

DELETE FROM `ActiveUsers` WHERE `LastPulse` < (NOW() - INTERVAL 2 MINUTE)

This will leave your ActiveUsers table so that only records for active users exist which you can now query against to get, along with any other information you want from this and any other table you can link to

SELECT `Username`, UNIX_TIMESTAMP(`FirstPulse`) AS `FirstPulse` FROM `ActiveUsers` ORDER BY `FirstPulse` ASC

(In PHP) You would then need to loop over the result set and build an array of users which would be converted to JSON with a call to json_encode() and print() ed along with an "application/json" header value so that jQuery can process it properly. This will of course differ between Java in implementation but the overall process of "create an array, convert it to a JSON string and print it out with a proper header specified" will be the same.

Ideally you want to keep the client as "dumb" as possible to any type of authentication process. In this example the client is blindly checking in with the server and triggering a cleanup of expired users just by asking for a new list of the active users.

If a 100% accurate list is mission-critical on a highly utilized site it may be necessary to lock the table while performing the maintenance portions. to ensure no queries for the user list occur while another thread is in the check-in phase.

(Wow, this turned into a Wall-O-Text)

You can periodically make an ajax call to the server and check how many have logged in currently. You could use setInterval for setting up a timer to fire the ajax request. The response would contain the no. of users active currently.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM