Problem with forward slash "/" in jQuery AJAX - javascript

I always wrote URLs used by AJAX calls in this way: "/Home/Save" with the forward slash in the beginning. Now this last project is being deployed to a virtual directory on a server. Thus, these URLs aren't working anymore, because instead of "example.com/VirtualDir/Home/Save", they would point to "example.com/Home/Save" which is wrong. I quickly fixed the problem by removing the first forward slash "/" in all occurrences of URLs in my JavaScript. All pages work great, except for one! When AJAX call happens on the problematic page, the specified URL gets appended to the page URL. I've spent a few hours yesterday and the whole morning today, and I cannot figure it out. There is absolutely nothing different about this page comparing to others. Has anyone had this problem before? Should I post my code?
EDIT: After banging my head on the keyboard for another few hours, I ended up implementing the following. I got an action in a common Controller that returns the result of Request.Url.GetLeftPart(UriPartial.Authority), which is your http://www.mysite.com. I render it inside my Layout page into a global JavaScript variable, _AppPath. Then, every AJAX call gets its URL like this: _AppPath + '/Controller/Action'. This works everywhere and I still don't know what the hack is the problem with that page. Cheers!

Can you change the Ajax requests so that they instead point to "/VirtualDir/Home/Save"?
If it helps your code, you could have a path variable, so that you can easily update the virtual directory path (or remove it) when you deploy it somewhere else. Or your code could read its location via the window.location.href property and work out things out from there.
It's not so useful to have paths relative to the current document (i.e. without the / slash prefix) because, as you are observing, some of the pages will then fail their requests, when those pages are at a different point in the site hierarchy. An absolute URL would be the one to go for (i.e. with a / slash prefix).
[UPDATED, based on comments below]
#Dimskiy, it doesn't so much matter that the server-side framework is .NET MVC, or that there are no actual folders for those URLs on the server. The browser will just respond according to the URL structure it sees.
So the things to look for are the URLs in the browser address bar for the different pages, and the URLs of the Ajax requests being made to the server (e.g. look for these in Firebug's "Net" panel). And compare the URLs, looking at the number of folders suggested by each URL.
It doesn't matter if there isn't an actual folder on the server. The browser can't tell, it can only look at the URL structure. If the JavaScript is making a call from a page called "foo" to an Ajax resources at "Home/Save", then the request will be routed to "foo/Home/Save". And if the request is made from page "foo/bar" then it will be routed to "foo/bar/Home/Save". That's a relative path - it's relative to the containing HTML document.
A request to an "absolute" path, say, "/Home/Save" (note the / slash prefix) will always go to the root of the domain, e.g. example.com/Home/Save. But since you need your request to go to the "VirtualDir" virtual directory, then your URL will become "/VirtualDir/Home/Save".

Related

Angular Removed # tags in urls. But not working as expected

I just removed # tag from my url of angular single page app.
I did like.
$locationProvider.html5Mode(true);
And It worked fine.
My problem is when I directly enter any url to the browser it showing a 404 error. And its working fine when I traverse throughout the app through links.
Eg: www.example.com/search
www.example.com/search_result
www.example.com/project_detail?pid=19
All these url's are working fine. But when I directly enter any of the above url's into my browser it showing a 404 error.
Please any thoughts on it.
Thanks in advance.
Well i had a similar problem. The server side implementation included Spring in my case.
Routing on client side ensures that all the url changes are resolved on the client side. However, When you directly enter any such url in the browser, the browser actually goes to the server for retrieving a web page corresponding to the url.
Now in your case, since these are VIRTUAL urls, that are meaningful on the client side, the server throws 404.
You can capture page not found exception at your server side
implementation, and redirect to the default page [route] in your app.
In Spring, we do have handlers for page not found exceptions, so i
guess they'll be available for your server side implementation too.
When using the History API you are saying:
"Here is a new URL. The other JavaScript I have just run has transformed the page into the page you would have got by visiting that URL."
This requires that you write server side code that will build the page in that state for the other URLs. This isn't a trivial thing to do and will usually require a significant amount of work.
However, in exchange for that work you get robustness and performance. When one of those URLs is visited it will:
work even if the JS fails for any reason (such as a dropped network connection or a client (such as a search engine) that doesn't support JS)
load faster than loading the homepage and then transforming it with JS
You need to use rewrite rules. Angular is an single page app, so all your request should go to the same file(index.html). You could do this by creating an .htaccess.
Assuming your main page is index.html.
Something like this (not tested):
RewriteRule ^(.)*$ / [L,QSA]
L flag means that if the rule matches, don't execute the next RewriteRule.
QSA means that the URL query parameters are also passed with the rewrited url.
More info about htaccess: http://httpd.apache.org/docs/2.2/howto/htaccess.html

How can history.pushstate allow a single point of entry for nested url paths

Sorry for the badly worded question.
PHP with apache uses index.php/index.html for directory urls like:
localhost = localhost/index.php or localhost/place = localhost/place/index.php
If I start with:
localhost/place
and I use a javascript history.pushstate to update a url with a long adress like:
localhost/place/subplace
then if I enter that url in the browser I'll go to localhost/place/subplace/index.php when I really wanted localhost/place/index.php to allow that url to be the only point of entry.
I'm using simple javascript(window.location.pathname or anchorNode.pathname) to retrieve the url path for use with ajax. This is used by a simple router similar to backbone.js to update the page. The javascript routing works and back/forward in the browser works. If only I could get it to work with the single point of entry for urls entered in the address bar.
To sum up:
I want a single point of entry for my php app to get all subdirectories.
At the single point of entry I want to run the javascript to acquire the path and use it to route the page with ajax.
I'm using history.pushState to update the url, but that messes with the single point of entry for the app when the directories are longer than the main directory. Basically I get a 404 page.
Right now I'm not too concerned with making it backwards compatible with browsers that don't have history.pushState. I just want this one thing to work.
As an addendum I would prefer working with regular paths in javascript and not the query string. Whether the page is loaded with the address bar or the history.pushState is used that's what I would prefer. I don't know if this can be handled with apache rewrite or what.
Similar questions:
How to cope with refreshing page with JS History API pushState
Ok. I'm making things too hard.
To get the routing to work on page load I need to do two things.
In the .htaccess file I can use apache rewrite to make all urls route to index.php?path=first/second/third.
When the page loads just concatenate the the new path in the query string to the javascript string that handles the route.
The javascript is still being used, and there's no duplication of functionality. Everything is good.
This also kind of answers this: How to cope with refreshing page with JS History API pushState

Force browser to reload all cache after site update

Is there a way to force the clients of a webpage to reload the cache (i.e. images, javascript, etc) after a server has been pushed an update to the code base? We get a lot of help desk calls asking why certain functionality no longer works. A simple hard refresh fixes the problems as it downloads the newly updated javascript file.
For specifics we are using Glassfish 3.x. and JSF 2.1.x. This would apply to more than just JSF of course.
To describe what behavior I hope is possible:
Website A has two images and two javascript files. A user visits the site and the 4 files get cached. As far as I'm concerned, no need to "re-download" said files unless user specifically forces a "hard" refresh or clears their cache. Once a site is pushed an update to one of the files, the server could have some sort of metadata in the header informing the client of said update. If the client chooses, the new files would be downloaded.
What I don't want to do is put meta-tag in the header of a page to force nothing from ever being cached...I just want something that tells the client an update has occurred and it should get the latest once something has been updated. I suppose this would just be some sort of versioning on the client side.
Thanks for your time!
The correct way to handle this is with changing the URL convention for your resources. For example, we have it as:
/resources/js/fileName.js
To get the browser to still cache the file, but do it the proper way with versioning, is by adding something to the URL. Adding a value to the querystring doesn't allow caching, so the place to put it is after /resources/.
A reference for querystring caching: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9
So for example, your URLs would look like:
/resources/1234/js/fileName.js
So what you could do is use the project's version number (or some value in a properties/config file that you manually change when you want cached files to be reloaded) since this number should change only when the project is modified. So your URL could look like:
/resources/cacheholder${project.version}/js/fileName.js
That should be easy enough.
The problem now is with mapping the URL, since that value in the middle is dynamic. The way we overcame that is with a URL rewriting module that allowed us to filter URLs before they got to our application. The rewrite watched for URLs that looked like:
/resources/cacheholder______/whatever
And removed the cacheholder_______/ part. After the rewrite, it looked like a normal request, and the server would respond with the correct file, without any other specific mapping/logic...the point is that the browser thought it was a new file (even though it really wasn't), so it requested it, and the server figures it out and serves the correct file (even though it's a "weird" URL).
Of course, another option is to add this dynamic string to the filename itself, and then use the rewrite tool to remove it. Either way, the same thing is done - targeting a string of text during rewrite, and removing it. This allows you to fool the browser, but not the server :)
UPDATE:
An alternative that I really like is to set the filename based on the contents, and cache that. For example, that could be done with a hash. Of course, this type of thing isn't something you'd manually do and save to your project (hopefully); it's something your application/framework should handle. For example, in Grails, there's a plugin that "hashes and caches" resources, so that the following occurs:
Every resource is checked
A new file (or mapping to this file) is created, with a name that is the hash of its contents
When adding <script>/<link> tags to your page, the hashed name is used
When the hash-named file is requested, it serves the original resource
The hash-named file is cached "forever"
What's cool about this setup is that you don't have to worry about caching correctly - just set the files to cache forever, and the hashing should take care of files/mappings being available based on content. It also provides the ability for rollbacks/undos to already be cached and loaded quickly.
i use a no-cache parameter for this situations...
a have a string constant value like (from config file)
$no_cache = "v11";
and in pages, i use assets like
<img src="a.jpg?nc=$no_cache">
and when i update my code, just change the $no_cache value, and it works like a charm.

javascript get Path Name represented in "browser address bar"

Is there any way to get the requested path (the path displayed in the browser address bar) vs the redirected path for a subdomain (hidden from the user) using javascript
I am using a shared javascript file (shared across multiple pages and sites) that determines the controller and action (MVC) using window.location.pathname but... I have just caught myself out as my deployment runs under sub-domains which I wasn't representing in the Visual Studio dev environment. the sub-domains on my host redirect to a /subdomain folder as is usually the case but now my window.location.pathname pulls back /subdomain/controller/action whereas the URL in the address bar is /controller/action
Obviously I can tweak my javascript to handle this situation - however there may not always be a subdomain (at least in my dev environment if nothing else - and I am dead against solutions like having "isdev" style flags throughout my code) so I have to have a fail-over for those instances which means things start to get a little more complicated thus being more prone to error.
Any suggestions greatly appreciated.
Btw I do not want to use values from .Net e.g. HttpContext... as my js is in an external file and I do not want to create a dependency on data in a view for it to work as this means every time I consume the js on a new page I have to remember to include the additional logic in the view for it to work, plus if I change my js file it may result in me having to refactor a bunch of views as well.
Cheers
Rob
window.location.href should return the entire URL that the site is currently at, including the subdomain e.g. http://subdomain.site.com/path/to/page.aspx
Alternatively you can use window.location.host and it will return everything except for the path, or window.location.pathname to return just the relative path to the file.
See the MDC article on window.location for more information: https://developer.mozilla.org/en/DOM/window.location

URL masking in JavaScript

I currently have the following JavaScript function that will take current URL and concatenate it to another site URL to route it to the appropriate feedback group:
function sendFeedback() {
url = window.location.href;
newwin = window.open('http://www.anothersite.com/home/feedback/?s=' + url, 'Feedback');
}
Not sure if this is the proper terminology, but I want to mask the URL in the window.open statement to use the URL from the current window.
How would I be able to mask the window.open URL with the original in JavaScript?
Things you could do:
1- Mask the external site in a html frame inside a document from your site.
(for example www.mysite.com/shortUrl/)
2-Send a Location HTTP header (real url will eventually be displayed)
Keep in mind that browsers do their best to show the real address due to phishing concerns.
I wouldn't use javascript if I wanted to mask url even thought it would work with javascript. You wouldn't get much benefits in that scenario.
The reason is simple:
javascript/jQuery = functions belongs to client-side (browswer/your PC/DOM)
links, url, http, and headers = functions belongs to Apache.
Apache is always top level above client-side. Whenever link is fired to SampeLink.html, Apache wakes up and reads the file, but links/urls are already owned before javascript could claim them. So, it is kinda of pointless if you tried to manipulate links in your javascript scripts, even though it works but weak.
I'd point you to this awesome approach: .htaccess and you will be surprised how powerful it is. If .htaccess is presented in the parent folder of SampleLink.html, Apache denies the DOM engine (your browser) from reading files until Apache have finished reading .htaccess.
With your scenario, .htaccess can do some work for you by rewriting links and send "decoy" links to the DOM engine, meanwhile keeping the orginial links/urls behind the curtain; and visitors would reach to 404page if they tried to break the app or whatever you are concerned about.
This is a bit complicated, but it never ceased to fail me. I use this as my "bible" http://corz.org/serv/tricks/htaccess2.php.

Categories

Resources