HttpRequest not to timeout on a lengthy request - javascript

I have the following Ajax call
function exampleAjax() {
$('#loadingImage').show();
var id = GetId();
$.ajax({
url: "../Controller/MyRequest?id=" + id,
type: "GET",
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (result) {
if (result.success === true) {
// Show Dialog Success
}
else {
// Show Dialog Failure
}
},
async: true,
processData: false
});
}
which calls below controller's method.
public async Task<JsonResult> MyRequest(string teamId)
{
bool success = false;
try
{
HttpResponseMessage response = await client.GetAsync(fullUriEndpoint)
if (!response.IsSuccessStatusCode)
throw new Exception(response.ReasonPhrase);
else
success = true;
return Json(new
{
success = success,
}, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new
{
success = success,
}, JsonRequestBehavior.AllowGet);
}
}
Because the request takes few minutes to process (this is totally fine, server needs to do a some processing that could take up to 5 minutes or more) then the client send back an exception although the task is still executed in the backend.
Is there a way I can manage this scenario without doing a fire and forget? I want to wait for the execution of this request until it gets completed.

As an option you may build a kind of polling process:
Client sends a request for "long operation".
Server starts the operation, gives it some id.
And immediately responds to the client that the operation has been started.
Then server listens for an API like GET /api/operation/:id to respond a status of given operation (done or in progress).
Client gets this pre-answer from (3) and run a timer, he requests the API from (4) every let's say 500ms until the operation is done or until N attempts are done.
Another option would be to provide bi-directional communication between server and client using WebSockets.

Probably your best bet would be to use SignalR. So ignoring that you should't run long running processes on asp.net.. I would recommend using something that does what you need in a different and easier way. SignalR abstracts Ajax/WebSockets so all you have to do is make calls either way (client to server or server to client).
Client to server (javascript):
$.connection.myHub.StartProcess()
Server
public class MyHub : Hub
{
public void StartProcess()
{
// DO WORK
// Call Client!
Clients().Client(id).ProcessFinished()
}
}
Client (Javascript)
$.connection.myHub.ProcessFinished = function(){
console.log('Long process finished!');
}

Related

How recognize javascript fetch() inside HandleErrorAttribute OnException?

In an asp.net mvc application, I'm successfully handling exceptions that occur when I make a jquery $.ajax call from javascript to a Controller. I want to handle errors in the same way when I make a javascript fetch() call from javascript, but I cannot figure out how to recognize that a fetch() call was made.
I'm using a class derived from HandleErrorAttribute to handle all Controller errors. This is done by adding the following line to global.asax Application_Start:
GlobalFilters.Filters.Add(new Areas.Insurance.Helpers.MyHandleErrorAttribute());
In MyHandleErrorAttribute I'm overriding the OnException method so that I can treat Ajax errors differently then regular get or post errors. If there is an ajax error my desire is to return an object that contains a guid and trigger the $.ajax "error:" callback in javascript. If there is an error caused by a javascript fetch() call I want the response.ok to return "false" and pass back an object that contains the error guid. If the error is not an ajax error or javascript fetch() error I want to redirect to our custom error page. The code looks like this:
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception == null)
return;
//log the error
Guid guid = MyClass.LogError(filterContext.Exception.GetBaseException());
if (filterContext.HttpContext.Request.IsAjaxRequest()
&& filterContext.Exception != null)
{
//this is an error from a $ajax call.
//500 is needed so that $ajax "error:" function is hit, instead of "success:"
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult()
{
Data = new MyErrorObject()
{
Guid = guid
}
,JsonRequestBehavior = JsonRequestBehavior.AllowGet
//JsonRequestBehavior.AllowGet prevents following sporadic error: System.InvalidOperationException: This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.
};
//this stops Application_OnError from firing
filterContext.ExceptionHandled = true;
//this stops the web site from using the default IIS 500 error.
//in addition must set existingResponse="Auto" ("PassThrough also works) in web.config httpErrors element.
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
else
{
//if condition to avoid error "Server cannot set status after HTTP headers have been sent"
if (!filterContext.HttpContext.Response.IsRequestBeingRedirected)
{
filterContext.Result = new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary
{
{"action", "Error500" },
{"controller", "Error" },
{ "Guid", guid}
});
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
filterContext.ExceptionHandled = true;
}
}
}
My problem is, when a call is made using javascript fetch(), "IsAjaxRequest" returns false, so the first "if" block is not hit. Instead I am going into the "else" block, which sets the Http Response to "OK" and does a redirect to my error page, both of which are not desired (when I get a fetch() error I want to return a 500 response, and of course the redirect has no effect).
How can I recognize that a javascript fetch() call was made? Is there something similar to "IsAjaxRequest"?
Here is what the javascript fetch looks like:
let url = '/myDomain/ThrowException';
fetch(url)
.then(function (data) {
if(data.ok){
//do something with data
}
else{
handleHttpErrorFunction(data);
}
})
.catch(function (error) {
handleFetchErrorFunction(error);
});
And here is the (successfully handled) jquery ajax call that I want to replace with a fetch() call:
$.ajax({
url: '/myDomain/ThrowException',
type: 'GET',
success: function (data) {
//do something with data
},
error: function (XMLHttpRequest, ajaxOptions, ex) {
ajaxerrorhandler(XMLHttpRequest);
}
See answer to related question at From server, how recognize javascript fetch() call was made (asp.net mvc). The fix is to send X-Requested-With XMLHttpRequest in the headers:
fetch('/MyDomain/MyControllerAction', { headers: { 'X-Requested-With': 'XMLHttpRequest' } })

PHP Thread telling to JavaScript that will sleep

The title is a little confuse, but my problem is:
Javascript do an AJAX Request to the PHP Controller. In the PHP Controller a Thread is created and started. The code is:
public function run() {
while(true) {
//Do Something...
//Know I want to tell Javascript that I have done the thing and I'm going to sleep.
sleep(10000);
}
}
So the JavaScript code is:
$.ajax({
type: 'POST',
url: "controllers/DatabaseController/",
data: dataObject,
success: function(response) {
//Do Something after the Thread Result
}
});
I am thinking that this problem it's impossible... Because the Thread runs and sleep after a time set by the client. And when the Thread runs, the client side need to see the results of the Thread.
How can I do this? The Javascript need to be in a loop like the PHP Thread?
The situation is:
- Thread do polling of the equipments status and after that the javascript change the icons status (green or red) of the equipments.
What you can do is:
Create two controller methods: One to start the thread the other one to check the status of it.
You make your ajax request to start the thread. Once the thread is started, you return a response, with a success/error message.
If the thread was started successfully, you will then make a second ajax request periodically to check the status of the thread.
You may also, in the first call, return the expected time the thread will sleep so you can adjust the time which the second ajax request will be made.
Edit (trying to clarify):
Let's say that your thread will check how much fuel the machine has. That thread will query the machine and will save that into a database.
The second method in the controller will query the database and fetch the results saved by the thread.
Example:
Controller:
class Controller
{
public function startThread()
{
// start thread
// return
}
public function checkStatus()
{
// query database for status
// return results
}
public function thread()
{
// check for machines status
// save the results into database
}
}
Javascript:
$.ajax({
type: 'POST',
url: "controller/startThread/",
data: dataObject,
success: function(response) {
// if success
setTimeout(function() {
$.ajax({
type: 'POST',
url: "controller/checkStatus/",
data: dataObject,
success: function(response) {
// your result will be here
})
}, 10000)
}
});
Solution:
I used the javascript function setInterval with the time that user set, who runs a function that do an ajax request to the php controller.
The Controller create a thread that do the polling of the equipments and die.

AJAX call in Scala Play: Data not transfered

I'm about to implement a Login using Google OAuth. I followed the official Google docs
The client does get a token from the Google server. But whenever I try to send it back to my server to store it, I do not seem to get data from the AJAX call. Here is my code:
function signInCallback(authResult) { //called when client has confirmed the Login dialog
if (authResult['code']) {
// Hide the sign-in button now that the user is authorized, for example:
$('#signinButton').attr('style', 'display: none');
console.log("signinCallback. Send code to server:")
console.log("Code = "+ authResult['code']);
console.log("performing AJAX call now...\n\n")
// Send the code to the server
$.ajax({
type: 'POST',
url: 'http://localhost:9000/storeauthcode',
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// Handle or verify the server response.
console.log("AJAX call --> success");
console.log(result)
},
processData: false,
data: authResult['code']
});
} else {
//There was an error.
console.log("AJAX call failed.")
}
I created a line in my routes file:
POST /storeauthcode controllers.Application.storeAuthCode
The method on the server:
def storeAuthCode = Action { request =>
Ok("storeauthcode called with queryString = "+request.rawQueryString)
}
The following is a console output of my Chrome browser:
hello.js:2 Welcome to your Play application's JavaScript!
(index):67 signinCallback. Send code to server:
(index):68 Code = <token deleted for privacy reasons>
(index):69 performing AJAX call now...
(index):77 AJAX call --> success
(index):78 storeauthcode called with queryString =
So although my browser gets a token back, I cannot store it on the server, because I don't get any data back.
Ok("storeauthcode called with queryString = "+request.body.asJson)
is also empty.
This one here also delivers an empty result:
def storeAuthCode = Action { request =>
Ok("storeauthcode called with queryString = "+request.getQueryString("data"))
}

Dojo tree - delay until server returns data

I have a server function that generates JSON representing part of the file system.
The server function is called once the user has selected an item from a pull-down list.
So far so good.
My question is how do I display the tree ONLY when the JSON data has been returned from the server? Please make your answer as verbose and complete as possible as I'm not a javascript pro by any means!
var serverFunctionComplete = false;
var x = serverFunction();
while(!serverFunctionComplete) {
//just waiting
}
setTimeout(function() {
serverFunctionComplete = true;//if the server doesn't respond
}, 5000);
This should get you started.
You could make ajax request synchronous using the sync : true property in the xhr object. This stops other code from executing until the response is recieved from the server and the callback is done executing.
require(["dojo/request/xhr"], function(xhr){
xhr("example.json", {
handleAs: "json",
sync: true
}).then(function(data){
// Do something with the handled data
}, function(err){
// Handle the error condition
}, function(evt){
// Handle a progress event from the request if the
// browser supports XHR2
});
});
However, this is typically not the best practice as asynchronous loading as one of the great things about javascript and ajax. It would be reccomended to do display your tree in the callback function in the xhr so your script does not get hung up polling for a response.
require(["dojo/request/xhr"], function(xhr){
xhr("example.json", {
handleAs: "json"
}).then(function(data){
// Display your Tree!
}, function(err){
// Handle the error condition
});
});
For general asynchronous thread management, refer to Dojo's Deffered class.

Ajax call (using jquery) gets no more responses after 5 minutes

In fact, I have a JavaScript application (jQuery) that is sending a request to a Java function which is supposed to send back data (success case) to my ajax function.
In the success case, I go on with my application; in error case, I stop my procedures and display the error message to the user.
But when the Java code takes more than 5 minutes to send a response to my Ajax call, this one (ajax code) doesn't (work / respond / go on /) get any response anymore ...
I tried setting up a timeout limit to 600000 ms (so 10 minutes) but I still get the same problem (and ain't got any error messages or output, which could have been helping me).
So if anyone's got an idea on the source of this problem, I'd be grateful.
Here is some piece of code if it may make it clearer :
JSP
$(document).ready(function() {
/* performing some layout changes */
//
preValidationDisplay();
}
function preValidationDisplay() {
/* performing some layout changes */
setTimeout("getValidationResult()", 500);
}
function checkReadLogFile() {
$.ajax({
url: logFileUrl,
cache: false,
success: function(result)
{
$("#progressBarToResize").width(
'' + parseFloat(result.trim()) + '%' );
}
});
}
function getValidationResult()
{
var timer = setInterval("checkReadLogFile()", 1000);
$.ajax({
url: '<s:url value="doValidation"/>',
type: "GET",
cache: false,
dataType: "json",
async: true,
//timeout : 600000,
success: function(result, status)
{
// Do something
},
error: function(jqXHR, status, errorStr){
// Do something
}
});
}
java
#RequestMapping(value = "/doValidation", method = RequestMethod.GET)
public String processValidationResults(HttpServletRequest request, HttpServletResponse response,
#RequestHeader("Connection") String conn) {
ValidationResult validationResult = null;
JSONObject resultJson = new JSONObject();
HttpSession session = request.getSession();
JSONObject progressMap = (JSONObject) session.getAttribute("progressMap");
String uploadedFilePath = progressMap.getString("filePath");
String realMimeType = progressMap.getString("realMimeType");
long fileSize = progressMap.getLong("fileSize");
String ctxPath = request.getContextPath();
// INVOKE the VALIDATION ENGINE
try {
validationResult = validationEngineService.getValidationResult(uploadedFilePath, ctxPath);
resultJson = JSONObject.fromObject(validationResult);
} catch (Exception e) {
validationResult = null;
resultJson.put("errorMsg", e.toString());
}
try {
response.getWriter().print(resultJson);
response.flushBuffer();
} catch (Exception e) {
}
return null;
}
When you're working with HTTP, never expect a connection to take longer than half a minute.
Either use WebSockets or Comet (long polling).
See, there are many parties that might decide to stop your connection:
web browser, firewall/router/isp, web server (eg: Apache), server scripting language (eg: PHP)
The only time I disable this on the PHP side is when I want PHP to keep running even after the user stopped the connection (which, by the way, I have enable yet another setting).
Without some code, i'm not sure if i could help much but have you tried checking which event is triggering the ajax call? I made a silly mistake once by sending an ajax request on keydown, i later found out that instead of keydown , i needed to use keyup since thats the event triggered once the value of the textbox is set to the text + key recently entered.
So you could try a keyup or change the event in jQuery. If this is on localhost, its not a good sign....first determine whats causing the problem, the frontend or backend.
Things to do:
1) Change event type in jQuery
$("#elem").live("keyup",function() {//send req});
2) Check apache log. If your on ubuntu or something similar, you can go to /var/log/apache2/error.log

Categories

Resources