I have model object:
module.exports = {
redirectTo: function(params, callback) {
callback(null, 'home/redirect_to');
}
}
Can I redirect user without loading page?
It will depend on variables, so redirecting not always needed. The only thing I need now is redirecting from server-side.
Server side redirection can be done by simply replying HTTP 302 to client.
If what you are asking is "How to go around server side redirection so that your Backbone callback can still be triggered?", then my solution will be following:
For example, when an user type a url http://yousite.com/blog/someid on his browser, and you want to use Backbone callback to handle his request. Then you can let your server return:
<script> window.location="http://yoursite.com#blog/someid"</script>
Note we replace a / into #.
Or, you can let your server return (fragment allowed in Location):
HTTP/1.1 302 Found
Location: http://yoursite.com#blog/someid
Then your Backbone callback will be triggered.
It can be done using this.redirectTo(url)
Related
I wish to give the client feedback before a redirect occurs, so they can store it in session storage, then when the cached page arrive from the service worker, they check session storage while the page is being rendered (not after!), and can handle the cached response accordingly.
I tried:
Adding a custom header to the response, but the client JavaScript can't read it for security reasons.
I have tried to edit the response directly. This only works for GET requests. Unfortunately when I sync a POST request, because it returns a redirect, so then it looks like a normal GET. So I need some additional way of saying, this is a GET after a sync POST, tell the user the POST was saved, its not just a normal "get the page"
Post Message, but slow as.
LocalStorage and SessionStorage is forbidden for the service worker
I could write to IndexedDB in the service worker, and then read from the client. But IndexedDB is such a confusing beast I really don't want to go down this route.
URL search parameters, redirect and url cleaning strategy became spaghetti code very quickly. The server would have to clean up URLs, and so would the service worker for the injected query args.
Is there any recommended machanism for relaying information to a client that would suite this purpose?
Side note about the post message being slow:
I currently use post message, but the problem is its really slow, and the reason I think is this:
Client attempts offline POST
Service worker serializes and stores it for when online again. In the fetch interrupt it responds with the cached response. It also calls an async postmessage to tell the client it was saved. Unfortunately if I await the postmessage, it errors out the fetch. So then one has to leave it to be async. Which means the post message happens only after the redirect
Client receive redirect response
Client redirects
Client paints the page
The cahed paged is showed
Only after about two seconds later it shows the 'was saved banner'
Heres some code if applicable:
Note: Orginally the code would set a value in the session storage when receiving the message (assumed it would receive the message before the redirect), and then pop it after the redirect at page render. However because the post message was coming so much later, I changed to performing the change on the page directly.
async function msgClientSyncSaved(event) {
const data = {
type: 'MSG_SYNC_SAVED',
};
const client = await getClient(event);
client.postMessage(data);
}
// Applicable parts of runFetch:
async function runFetch(event) {
const urlObj = new URL(event.request.url);
if (utils.getIsMethodTx(event.request.method)) {
// If a Sync URL
const clonedRequest = event.request.clone();
const response = await new strategies.NetworkOnlyStratey(log, event, cacheMutator).run();
if (!response.isDefaultResponse && !response.isCachedResponse) {
event.waitUntil(syncAllRequests());
return response;
} else {
const [syncKey, syncValue] = settings.PWA_SYNC_POST_URL_PARAM.split("=");
if (urlObj.searchParams.get(syncKey) === syncValue) {
// A failed POST, that requires SYNCING
console.log(`SW: Sync later: ${event.request.method} to ${event.request.url}`);
event.waitUntil(storeRequest(clonedRequest)); // no need to wait for this to finish before returning response
event.waitUntil(msgClientSyncSaved(event)); <--- HERE message client
// After a post, return a redirect
urlObj.searchParams.delete(syncKey);
const redirectUrl = String(urlObj);
// 302 means GET the redirect, 307 means POST to the redirect
console.log('REDIRECT TO', redirectUrl)
return Response.redirect(redirectUrl, 302);
}
}
}
}
function handleFetch(event) {
event.respondWith(runFetch(event));
}
self.addEventListener("fetch", handleFetch);
Reciever on client side:
async function handleMessage(event) {
switch (event.data.type) {
case 'MSG_SYNC_SAVED':
document.body.setAttribute('data-pwa-cached-page', 'true data-tx')
break;
}
}
navigator.serviceWorker.addEventListener("message", handleMessage);
I want to use an API in my meteor app. The API is restricted to a few requests per second per unique IP.
Does anyone know if the server IP or the user IP is used, when I make an API call in Meteor.methods like this
Meteor.methods({
searchTerm: function (term, lang) {
var parameters = {
"api_key": Meteor.settings.API
};
try {
var result = HTTP.call("GET", apiLink, { params: parameters });
return result.data;
} catch (e) {
return e;
}
}
}
Thanks in advance.
As already noted in the comments, if this code (the methods call itself) is runs on the server, then the method call (later with Meteor.call) is like a remote procedure call and the HTTP will be executed on the server only. If, however, this code, the methods call, is invoked on both the client and the server, then that defines a stub (http://docs.meteor.com/#/full/methods_header). That stub is executed in parallel on the client and the server. It is meant to help with latency compensation. I don't think you want that in this case though, since you are more concerned with the number of API requests. So I would suggest to leave it where it is right now (in the server folder somewhere). That way you can be sure that it will only execute on the server and not the client, and hence use the server IP.
When running an angularjs application, the user access may be withdrawn from the server side. In this case, every request results in a http 302 redirect and a login html (no partial) page. Since angular does expect whatever it was requesting in case the access would still be given, it breaks as it may expect a json string but gets the html login page.
Is there anything I can do do catch this event (listen to redirects, figure out whether html is returned, etc) and do a "hard" refresh of the redirect url?
Since you can't interfere an ajax 302 response and redirect to an error page, you will need to be a little creative.
You can add a header or a different response code to your relevant responses and add an interceptor on the client end.
The interceptor is a module that every ajax request\response goes throught.
You can add code that will look for that header and simple perform a $window.location.href to the login page.
Read here about interceptors.
Check this example out - It handles 401 responses.
If I get you right you are talking about the $http Service from AngularJS.
If thats the point, you could transform the response by yourself and check if its valide JSON like this:
$http({
url: '...',
method: 'GET',
transformResponse: function (reponse) {
var ret = [];//if the return stays empty, the repsonse may be HTML
try {
ret = JSON.parse(reponse);
} catch (error) {
//here you could check for the error
}
return ret;
}
}).success(function(answer){
if(answer.length === 0){//its empty, so its probably HTML
$window.location.reload();//refresh page here
return;
}
//its JSON with content!
});
Meteor's HTTP package is a wrapper around mikeal's request, and it supports the followRedirects option. But how can one find out what the final URL is, after the 3xx redirect responses have been followed (and the request didn't fail because of lack of a cookie jar)?
With request, the final URL is in response.request.href. But with Meteor... ?
Here's the Meteor code:
if (Meteor.isServer) {
Meteor.startup(function () {
var url = 'http://google.com';
var result = HTTP.call("HEAD", url, {
followRedirects: true
});
console.log(result); // nothing here hints at the final URL
});
}
I've created a package that does this - http-more.
Turns out Meteor doesn't pass back the request object within the response, and given the history of rejected PRs concerning enhancements to the HTTP package, I've just implemented that option separately.
I know that you can't, when using an XMLHttpRequest, intercept a redirect or prevent it, as the browser will transparently follow it, but is it possible to either
A. Determine whether a request redirected, or
B. Determine where it redirected to? (assuming that the response gives no hints)
Example code:
$.post("/my-url-that-redirects/", {},
function(response, statusCode, xmlHttpRequest){
//Somehow grab the location it redirected to
}
);
In my case, firebug will first show a POST to the url, then a GET to the redirected url. Can that GET location be captured?
1) Use different status code than 301 (2**) (if request by ajax) and handle redirection on client side:
var STATUS = {
REDIRECT: 280
};
$.post('/redirected', {}, function(response, status, request) {
if (status == STATUS.REDIRECT) {
// you need to return the redirect url
location.href = response.redirectUrl;
} else {
$('#content').html(request.responseText);
}
});
2) DO NOT REDIRECT:
I use that in "redirect pattern" = redirecting after post request (you don't want to allow user to refresh the post request, etc..)
With ajax request, this is not necessary, so when the post request is ajax, I do forward instead (just forward to different controller - depends on your server-side framework, or what you are using...). POST requests are not cached by browsers.
Actually, I don't know what's the reason you need that, so this might not be so useful for you. This is helpful when server returns different responses for ajax requests than common requests, because when browser redirect ajax request, the redirected request is not XMLHttpRequest...
[updated]
You can access headers (of redirected request) like that:
$.post('redirected', {}, function(r, s, req) {
req.getAllResponseHeaders();
req.getResponseHeader('Location');
});
There should be 'Location' header, but it depends on the server, which headers are sent back...
After 4 years now it's possible to find the last redirect location using responseURL from XHR instance in Chrome 42+ (Opera 29+) and Firefox 39+ but it's not available in IE, Edge or safari yet.