Relative Path Problems in Javascript Ajax call
Asked Answered
L

5

22

Okay, I have a JavaScript file with the following functions:

function AskReason() {
    var answer = prompt("Please enter a reason for this action:", "");
    if (answer != null)
        DoReason(answer);
}

function createXMLHttpRequest() {
    try {
        return new XMLHttpRequest();
    }
    catch (e)
    { alert('XMLHttpRequest not working'); }
    try {
        return new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e)
    { alert('Msxml2.XMLHTT not working'); }
    try {
        return new ActiveXObject("Microsoft.XMLHTTP");
    }
    catch (e)
    { alert('Microsoft.XMLHTTP not working'); }
    alert("XMLHttpRequest not supported");
    return null;
}

function DoReason(reason) {
    var xmlHttpReq = createXMLHttpRequest();
    var url = "/Shared/AskReason.ashx?REASON=" + reason;
    xmlHttpReq.open("GET", url, true);
    xmlHttpReq.send(null);
}

This line:

    var url = "/Shared/AskReason.ashx?REASON=" + reason;

Is what is causing the problem.

In VS 2010 debugging the app - this call works to my ashx handler.

When I move the project to a virtual directory - example http://localhost/myapp

this code will break and I have to change the javascript to this:

var url = "http://localhost/myapp/Shared/AskReason.ashx?REASON=" + reason;

Any ideas on how I can fix this to work in both environments or just accept the manual change when I deploy apps to servers?

Thanks, Mike

Luciusluck answered 23/2, 2011 at 14:42 Comment(1)
Not a fix, I'll look more in a min - but it is a very bad idea to roll your own AJAX method [for security reasons among others] - please look at a library like prototype or jQuery. Or since you're using .NET - use the built in libraries (which are effectively jQuery)Layby
W
27

Pointy's way works, but you have to know in advance where you're going to deploy it.

Alternately, simply don't start the relative path with a /:

var url = "Shared/AskReason.ashx?REASON=" + reason;

That will be resolved relative to the current document's location. So if the current document is:

http://localhost/myapp/index.aspx

...then that will resolve to

http://localhost/myapp/Shared/AskReason.ashx?REASON=foo
Wellwisher answered 23/2, 2011 at 14:46 Comment(3)
This doesn't work for me because the current page calling the JS is in a sub folder... but if everything was in the same folder it would work!Luciusluck
@MDV2000: You can still use relative paths in your structure. For instance, if the source is http://localhost/myapp/subfolder/index.aspx, you can use ../Shared/AskReason.ashx to get to http://localhost/myapp/Shared/AskReason.ashx. Multiple ../../ are fine too. I do recommend keeping all paths within the app relative rather than "rooted".Wellwisher
I actually found another way. In my ASP.NET codebehind, I set the OnClientClick of the button to my JS method. I added a param to the method and pass the server URL + Virtual Directory name and so in the JS code I just concatenate the param value to the url to get the path I want.Luciusluck
A
8

Paths that start with a "/" (and no protocol & host) are relative to the root of the host. If you deploy such that your application is at "http://whatever/myapp", then your root-relative paths have to start with "/myapp".

When you're working in a server-side environment that involves some sort of page template mechanism, a common trick is to have that part of the path be some kind of configuration variable so that you can write pages with paths like:

<a href='${root}/something/something'>click me</a>

Then that "root" variable is expanded based on configuration to "/myapp" or whatever.

Adige answered 23/2, 2011 at 14:45 Comment(0)
S
4

I had a similar problem where an absolute URL was needed but the reference broke when going from localhost to the production server. I resolved it by checking if a "localhost" string exists in:

var environ = window.location.host;

Then you can simply do:

if (environ === "localhost") {
    var baseurl = window.location.protocol + "//" + window.location.host + "/" + "shared/";
} else {
    var baseurl = window.location.protocol + "//" + window.location.host + "/";
}

Then you can add baseurl in front of whatever url you need to reference.

Surbase answered 4/11, 2014 at 19:49 Comment(0)
L
2

The url

var url = "/Shared/AskReason.ashx?REASON=" + reason; 

Is looking for the file in the root directory [since it is an absolute path], effectively

http://localhost/Shared/AskReason.ashx

You should include the name of the virtual directory OR determine the appropriate structure:

Starting without the / will give you a relative path ... if you need to navigate directories use ../Shared/ style of notation, or finally use your servers Directory command to determine your current path.

Layby answered 23/2, 2011 at 14:53 Comment(0)
G
2

I have the same issue with ASP.NET MVC with my AJAX call on a separate .js file. This is how it looks:

 return $.ajax({
            type: "POST",
            url: '/Dashboard/Execute',
            contentType: "application/json; charset=utf-8",
            data: filter,
            dataType: "json",
        });

This works fine on my local, of course. But when deployed on a subdirectory in IIS, e.g.

wwwroot/appsite/subdomainfolder/

This will trigger 404 Not Found as it didn't attach the subdomainfolder on the URL.

If I remove the

"/"

at the beginning of the URL, it will generate it like this one:

http://localhost/subdomainfolder/Dashboard/Dashboard/ExecuteReader

Which again will trigger the 404 Not Found issue.

So here are the two options for my workaround:

Remove the backslash and remove the name of the controller (Dashboard on this case):

return $.ajax({
            type: "POST",
            url: '/Execute',
            contentType: "application/json; charset=utf-8",
            data: filter,
            dataType: "json",
        });

Or, stay as it is, just add double period at the beginning of the URL:

return $.ajax({
            type: "POST",
            url: '../Dashboard/Execute',
            contentType: "application/json; charset=utf-8",
            data: filter,
            dataType: "json",
        });
Gnni answered 21/10, 2019 at 18:34 Comment(1)
Thanks. This worked for me, as long as it's calling a method within the same controller.Flexed

© 2022 - 2024 — McMap. All rights reserved.