I have a portion of my web application that uses AJAX. I am using the JQuery AJAX call to add and remove items from the users shopping cart, and it works fine. The URL that I pass as a parameter in the AJAX call is the url-mapping defined in the web.xml file, minus the leading forward slash.
I tried to replicate this with another place in the application where I would like to use AJAX, but this time, the Servlet GET is not even being called at all. I have alerts in the javascript function, so I know the function is being called. Is there a way that I can see (within the ajax function call) what the fully qualified URL is that the GET request is being made to? Also, what is the 'rule' with respect to the AJAX URL? Is there a way that I can get to the context root? My Servlet is mapped to www.mydomain.com/contextRoot/un
I would rather not have to hardcode the context root into the function call, that way if it ever changes, I don't have to update all my javascript functions.
The "rule"
Ajax requests (or any http request from the page) that does not start with a / (or the full domain path) is relative to the current HTML file path.
How to view GET requests
Use the debugging tools in Chrome/Firefox or something like Fiddler2
How to get server root
If it is a simple www.host.com:
var root = location.protocol + '//' + location.host;
(Not sure if this works for context based domains).
You do not mention what server technology you are using, but if you are using MVC/Razor you can inject the server root into a Javascript variable with something like this in your master page header:
<script type="text/javascript>
window.domainRoot = "#(Url.Content("~/"))";
<script>
this injects a javaScript line like:
window.domainRoot = "http://www.mydomain/mycontext/";
you can then reference window.domainRoot from any JavaScript code.
If you are using PHP there will be an equivalent way to inject the server root.
A simple browser debugger (F12) and you can read the network traffic send.
From here it is possible to see all the details (sent and/or received)
I think The url plus parameter is contextRoot/un?para=*.
Related
I have a javascript file named myscripts.js in the "scripts" folder of my webserver. It could be accessed with this:
http://www.example.com/scripts/myscripts.js
Within myscripts.js is a javascript function which makes a XMLHttpRequest call to somemethod.html of my website. Here is the calling code:
xmlhttp.open("GET","somemethod.html",false);
99% of the time everything works fine. But I am finding some browsers are prepending "scripts/" to the call. So the result is a call like this:
http://www.example.com/scripts/somemethod.html
when it should be this:
http://www.example.com/somemethod.html
This is a custom built webserver (i.e. I basically handle ALL requests).
Should my webserver be able to handle this? Or is this just some fluky browser that I should not worry about?
Should I not be using "relative" paths in the javascript? And instead use absolute calls in the java script? e.g.: instead of "somemethod.html" it should be coded like this:
xmlhttp.open("GET","http://www.example.com/somemethod.html",false);
It's absolutely fine (and overwhelmingly the standard of practice) to use relative paths in the JavaScript, just be aware of what they're relative to: The document in which you've included the JavaScript (not the JavaScript file.) You seem clear on this, but just emphasizing.
I've never seen a browser get this wrong. It's possible the requests you're seeing are from a poorly-written web crawler looking at the source of the JavaScript rather than doing something intelligent like figuring out where/how it's run.
Just for clarity, though, about the relative thing (more for lurkers than for you):
Given this structure:
foo.html
index.html
js/
script.js
In that structure, if you include script.js in index.html:
<script src="js/script.js"></script>
...then use code in that script file to do an XHR call, the call will be relative to index.html, not script.js, on a correctly-functioning browser.
I never use relative requests, I built my own url handing js code to build up and pass urls around with a 'toString' method to give me exactly the url I need.
Also as an aside, try not to use synchronous XHR calls anymore, ideally you should use async and call backs, it's a pain, but it's for the best.
client . open(method, url [, async = true [, username = null [, password = null]]])
Sets the request method, request URL, and synchronous flag.
Throws a "SyntaxError" exception if either method is not a valid HTTP method or url cannot be parsed.
Throws a "SecurityError" exception if method is a case-insensitive match for `CONNECT`, `TRACE` or `TRACK`.
Throws an "InvalidAccessError" exception if async is false, the JavaScript global environment is a document environment, and either the timeout attribute is not zero, the withCredentials attribute is true, or the responseType attribute is not the empty string.
source: http://xhr.spec.whatwg.org/#the-open%28%29-method
I am creating a pixel image in javascript, by creating the image tag and injecting it into the DOM.
The tag looks something like this:
<img style="height:0;visibility:hidden;display:none;" src="http://xyz.com/pixel.aspx">
As you can see, this tag will actually call an ASP.Net page, which will do some processing and write back a pixel like this:
byte[] _imgbytes = Convert.FromBase64String("R0lGODlhAQABAIAAANvf7wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
Response.ContentType = "image/gif";
Response.AppendHeader("Content-Length", _imgbytes.Length.ToString());
Response.Cache.SetLastModified(DateTime.Now);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.BinaryWrite(_imgbytes);
What I need is a way to either pass a small piece of data (a GUID value generated in the javascript before the pixel request) to the server or pass some data (a different GUID generated in the pixel aspx code) back to the browser in a way in which it can be picked up by javascript.
Caveats:
Cannot use query string, because the pixel needs to be cachable, and if query string is different the pixel will not be pulled from the browser cache (filename will be different) on subsequent requests.
Cannot use cookies, pixel request is on different root domain than the application, and need this to work in the case where third party cookies are disabled.
Cannot use AJAX, because don't want to worry about cross-domain issues
Use http://xyz.com/pixel.aspx/your-guid-here. Then it's just a matter of configuring your webserver and/or application so it doesn't result in a 404 error but executes your aspx code.
I resolved this problem myself.
Instead of an image, I went with a remote script request. So my injected tag looks like this:
<script async src="http://xyz.com/tracking.aspx"></script>
Then, in my aspx, I have the following:
string script = "(function(){Complete('" + guidValue + "');})();";
Response.ContentType = "application/javascript";
Response.Cache.SetLastModified(DateTime.Now);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Write(script);
When the response returns to the browser, the Complete method (which resides in a javascript file already loaded by the page) executes with my guid parameter. This enables my page to have full access to the guid.
Also, since the request URL never changes, the script is properly cached by the browser.
Voila.
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".
I'm looking to build a cross-site bookmarklet that gets a highlighted word, passes it to a CodeIgniter method (domain.com/controller/method), and returns the definition via a dictionary API. I've got a skeleton working well on a single domain, but I'm looking to expand it to use JSONP cross-domain. But I feel unclear.
I know I need to load a script from a remote location and inject it in the current context. And I believe I'll need to get the highlighted word on a page, then call a URL that looks like domain.com/controller/method/word to get that script. Then it gets foggy.
I think I essentially have two questions:
Where do I include the necessary javascript to handle the parsing and passing of the word via XMLHTTPRequest? I think this will be the SRC of the script that I'll inject in the new context. Is this somehow within my relevant CodeIgniter method? Or does this new script come from a random location on the same server as the relevant method and simply call to it?
Answer: This is not supplementary to XMLHTTPRequest, this is in lieu of it, so that step is completely removed. The new script calls to the method, passes requisite information via query strings, and receives the JSON array in response.
Am I correct in understanding I'll eventually pass the JSON response from the method back as word(json_encode($array));?
Answer: Yes, I'll pass that back as callbackFunctionName(json_encode($array));.
Do I need to set headers, as done here?
Update
I included the answers to two of my three answers above. If someone can explain things thoroughly, of course I'll mark their answer as correct, else I'll elaborate my stumbling blocks in an answer. I still have no idea where I write the callback function and what I'll be doing with that in JS.
Thanks so much for any help you can give on this.
First set your bookmarklet with a link you can drop on the bookmark bar:
<html>
<head></head>
<body>
load
</body>
</html>
Replace the url by your script, it will be loaded and running on the host page.
However it sits now in the hosted page, and can't call your server with XMLHTTPRequest as the domains do not match.
Here comes JSONP.
In the loaded script, you can put a function eg: function srvCallback(json){...}
When you want to call your server you will inject it as a script using a similar function as in the bookmarklet above:
function jsonp(src){
var s = document.createElement('script');
old = document.getElementById('srvCall');
old && document.body.removeChild(old);
s.charset = 'UTF-8';
s.id = 'srvCall';
document.body.insertBefore(s, document.body.firstChild);
s.src = src + '?' + new Date().getTime();
}
Inject your request, eg:
jsonp('http://domain.com/controller/method/word')
The server should respond something like:
srvCallback({word:'hello'});
And finally the function srvCallback is automatically called, inside the function you get your JSON and show the result to the user.
Very simple Ajax request taking employee id and returning the user info as HTML dumb.
Request ajax("employee/info?emp_id=3543")
Response id = 3543name = some name
This is just another simple JS trick to populate the UI. However i do not understand how something like below is equally able to execute correctly and dump the HTML code.
<script type="text/javascript" src="employee/info?emp_id=3543" />
When page encounters following code it executes like the ajax request is executed and dumps code into page. Only difference is its no more asynchronous as in case of Ajax.
Questions :
Is this correct approach ? its +ves and -ves.
Which are the correct scenarious to user it?
Is this also means that any HTML tag taking "src" tag can be used like this?
I have used this kind of javascript loading for cross domain scripting. Where it is very useful. Here is an example to show what I mean.
[Keep in mind, that JS does not allow cross domain calls from javascript; due to inbuilt security restrictions]
On domain www.xyz.com there lies a service that give me a list of users which can be accessed from http://xyz.com/users/list?age=20
It returns a json, with a wrapping method like following
JSON:
{username:"user1", age:21}
If I request this json wrapped in a method like as follows:
callMyMethod({username:"user1", age:21})
Then this is a wrapped json which if loads on my page; will try to invoke a method called callMyMethod. This would be allowed in a <script src="source"> kind of declaration but would not be allowed otherwise.
So what I can do is as follows
<script language="javascript" src="http://xyz.com/users/list?age=20"></script>
<script language="javascript">
function callMyMethod(data)
{
//so something with the passed json as data variable.
}
</script>
This would allow me to stuff with JSON coming from other domain, which I wouldn't have been able to do otherwise. So; you see how I could achieve a cross domain scripting which would have been a tough nut to crack otherwise.
This is just one of the uses.
Other reasons why someone would do that is:
To version their JS files with
releases.
To uncache the js files so that they are loaded on client as soon as some changes happen to js and params being passed to URL will try to fetch the latest JS. This would enable new changes getting reflected on client immediatly.
When you want to generate conditional JS.
The usage you have specified in example wouldn't probably serve much purpose; would probably just delay the loading of page if processing by server takes time and instead a async ajax call would be much preferred.
Is this correct approach ? its +ves
and -ves.
Depends whether you want to use asynchronous (ajax) way or not. Nothing like +ve or -ve.
The later method takes more time though.
Which are the correct scenarious to
user it?
Ajax way is the correct method there in that sense.
Is this also means that any HTML tag
taking "src" tag can be used like
this?
src is used to specify the source path. That is what it is meant to do.