I'm calling the method in my page:
var dfd = $.Deferred(
$.getJSON(serviceAddress)
.done(function (result, status) {
bo.BusinessObject.DtosToaKoArray(result, resultList);
dfd.resolve(resultList);
})
.fail(function (result, status) {
logger.logError(result);
dfd.reject(result);
}));
return dfd;
After calling the JSON, the firebug shows that HttpRequest was successfull and the response header is like:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcV29ya3NwYWNlc1xNZWhyYW5cSW5mcmFzdHJ1Y3R1cmVcTWFpblxTb3VyY2VcSW5mcmFzdHJ1Y3R1cmVcU291cmNlXENhcmFuZS5HYWxheHkuV2ViQXBpXGFwaVxEYXRhUHJvdmlkZXJcTGlzdFNlcnZpY2Vc?=
X-Powered-By: ASP.NET
Date: Sun, 04 Aug 2013 05:57:39 GMT
Content-Length: 6684
but the problem is that instead of done callback, the fail callback is called with this result:
Object { readyState=4, status=404, statusText="error"}
What is wrong about my call that fails the successful http request?
Edit1.
My website (MyApp.Web) is on localhost:2771 and the calling service is in another project (MyApp.WebApi) on the localhost:4143
You will definitely run into some hurdles trying to make cross-origin requests. That includes port-to-port.
The solutions also depend on the service and what features it supports.
JSONP (or, JSON with Padding)
The service would need to accept a callback and output the JSON wrapped in a function call:
// http://...?callback=completeRequest
completeRequest(["json", "data"]);
The parameter can be a different name than callback. But, you can instruct jQuery to use it by including a placeholder parameter (...=?):
$.getJSON(serviceAddress + "?callback=?")
This can also be used in any browser as it's requested as a <script src> and the JSON will be parsed as JavaScript literals.
CORS
The service will need to support preflight, OPTIONS requests and respond with Access-Control-Allow-* headers.
Also, while most current browsers support CORS, this can be limited if you need to support older editions.
Otherwise, you'll need to create a proxy destination in your application (localhost:2771) that makes the cross-origin request server-side to the service (localhost:4143).
It might not be finding your target page and that's why you might be getting a 404 in your result object. Make sure that your serviceAddress is correct.
In addition to that When you specify: dataType: 'json' jQuery will fire the error event if the response cannot be parsed as JSON(despite the 200 reply). Make sure that the data returned from the server is valid JSON, you might want to validate the structure manually via JSONLint.
It might be any of these 2 problems.
Related
As you might know, RFC 6265 indicates that it is allowed to have multiple headers with the Set-Cookie name.
However, Fetch API doesn't allow to do that because all the methods exposed by its Headers interface (including get(), set(), append(), entries() and all the rest) have been implemented to merge the values of all the headers with the same name into a single header separated by commas.
For example, if we do this:
var headers = new Headers();
headers.append('content-type', 'text/plain');
headers.append('set-cookie', 'test1=v; Max-Age=0');
headers.append('set-cookie', 'test2=v; Max-Age=0');
headers.append('set-cookie', 'test3=v; Max-Age=0');
and then we try to read the set-cookie values using get('set-cookie'), or by iterating the headers variable using entries(), we get this:
'set-cookie' : test1=v; Max-Age=0, test2=v; Max-Age=0, test3=v; Max-Age=0
Please notice that the same wrong behaviour also happens if we try to read or manipulate an existing response object having multiple headers with the same name (i.e. created by other frameworks that arguably support such allowed behavior): in other words, it seems like the Fetch API is completely unable to properly deal with such scenario.
Now, while this behavior is desired for some headers, such as Accept, the Set-Cookie header is not parsed correctly by most browsers (including Chrome and Firefox), thus resulting in cookies not being correctly set.
Is that a known bug? If that's the case, is there an usable workaround that can be used to overcome this?
This is a known "issue" with the standard. It's actually the first note of the Fetch API standard in the Headers section:
Unlike a header list, a Headers object cannot represent more than one Set-Cookie header. In a way this is problematic as unlike all other headers Set-Cookie headers cannot be combined, but since Set-Cookie headers are not exposed to client-side JavaScript this is deemed an acceptable compromise. Implementations could chose the more efficient Headers object representation even for a header list, as long as they also support an associated data structure for Set-Cookie headers.
You can read more or even raise your own issue in the spec's repo.
There are already a few issues discussing the Set-Cookie case at length though:
https://github.com/whatwg/fetch/issues/973
https://github.com/whatwg/fetch/issues/506
https://github.com/whatwg/fetch/issues/189
https://lists.w3.org/Archives/Public/www-archive/2016Jan/thread.html
You mentioned using workarounds, but this really depends on your use-case.
The note mentions using a secondary structure to handle those.
If you really want to store those cookies in a Headers object, you could add custom headers to store them:
new Headers([
['X-MyOwn-Set-Cookie-1', 'cookie1=value1'],
['X-MyOwn-Set-Cookie-2', 'cookie2=value2']
]);
Obviously, this is not an acceptable solution for the standard, but maybe your practical considerations might be in line with such a compromise.
As pointed out by this note and #Barmar in the comments, you usually use Set-Cookie from the server, not the front-end.
For instance, there's no problem setting multiple Set-Cookie with express:
test.js
const express = require('express');
const app = express();
const cookies = [
{ key: 'cookie1', value: 'value1' },
{ key: 'cookie2', value: 'value2' },
];
app.get('*', (req, res) => {
console.log(req.url);
for (const { key, value } of cookies) {
res.cookie(key, value, { expires: new Date(Date.now() + 1000 * 60), httpOnly: true });
}
res.status(200).send('Success');
});
app.listen(3000, () => console.log(`Listening on http://localhost:3000/`));
Terminal 1
$ node test.js
Listening on http://localhost:3000/
Terminal 2
$ curl -v http://localhost:3000/
[...]
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Set-Cookie: cookie1=value1; Path=/; Expires=Tue, 04 Aug 2020 19:45:53 GMT; HttpOnly
< Set-Cookie: cookie2=value2; Path=/; Expires=Tue, 04 Aug 2020 19:45:53 GMT; HttpOnly
< Content-Type: text/html; charset=utf-8
[...]
I'm using a Flask rest api where I've a method that I call from AngularJS with $resource factory.
I'm using now data to try it, this is the simplified code in the server:
return jsonify({'teacher': 'Tom'})
And in AngularJS, in a controller where I want to get data:
var teacher = $resource('http://localhost:8001/entities/teacher/:id');
teacher.get({id: 1}).$promise.then(function(teacher) {
// success
$scope.teacher = teacher;
}, function(errResponse) {
// fail
console.log('fail')
console.log(errResponse)
});
And this is the log in web browser console:
fail
Object { data: null, status: -1, headers: fd/<(), config: Object, statusText: "" }
But however I can see the request in network console with data in response with 200 status code, because of this I think that I don't know how read this data from $resource response, I've search info about this but I don't know how if I can see the data the resource give mi a fail error.
Any idea?
I know that I should to have this code in a service in another file, it's only a sample to find the solution.
Thanks!
Update:
I think that the problem is in the headers that I received from the server. If I try to use $http with a url that I found as example this work perfect, but when I try the same with my own server this fail even though I can see the response (and it's fine in the network console and it's fine with curl test) I think that the problem is in the headers, maybe $http or $resource needs a specific headers. I' ve updated the original question, I hope that someone can help me. I'm sure that the response is application/json.
This is the test url:
http://jsonplaceholder.typicode.com/users
and the header that is returned is:
Cache-Control
public, max-age=14400
Content-Encoding
gzip
Content-Type
application/json; charset=utf-8
Date
Mon, 03 Oct 2016 07:43:11 GMT
Etag
W/"160d-MxiAGkI3ZBrjm0xiEDfwqw"
Expires
Mon, 03 Oct 2016 11:43:11 GMT
Pragma
no-cache
Server
cloudflare-nginx
Vary
Accept-Encoding
Via
1.1 vegur
X-Firefox-Spdy
h2
X-Powered-By
Express
access-control-allow-credentials
true
cf-cache-status
HIT
cf-ray
2ebec303f9f72f7d-MAD
x-content-type-options
nosniff
And my header is:
Cache-Control
no-cache
Content-Length
35
Content-Type
application/json
Date
Mon, 03 Oct 2016 08:26:00 GMT
Expires
Fri, 01 Jan 1990 00:00:00 GMT
Link
Server
Development/2.0
I'm using a Google App Engine developer Server (I don't know if this is relevant).
I have a simple piece of code that finds the groups available to a user on Yammer using the Yammer JavaScript api and it looks a little like this:
yam.platform.request({
url: "groups.json?mine=1",
method: "GET",
success: function (data) {
callback(data);
},
error: function (error) {
console.log(error);
},
});
The call is carefully wrapped so it only ever happens once per page request, but it appears to succeed or fail on a totally arbitrary basis. The response either looks like this:
Response Headers
Cache-Control:no-cache
Connection:keep-alive
Content-Type:application/json; charset=utf-8
Date:Wed, 26 Nov 2014 17:32:42 GMT
P3P:CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Server:nginx
Status:429
Transfer-Encoding:chunked
X-Date:1417023162896
X-Runtime:0.032459
X-UA-Compatible:IE=Edge,chrome=1
or like this:
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https://my-access-origin.sharepoint.com
Access-Control-Expose-Headers:content-type, network_id, authorization, x-csrf-token, www-authenticate, x-xss-protection, ETag
Cache-Control:max-age=0, private, must-revalidate
Connection:keep-alive
Content-Type:application/json; charset=utf-8
Date:Thu, 27 Nov 2014 12:17:38 GMT
ETag:"123a45b67cd89ef01234ab45cd67ef"
P3P:CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Server:nginx
Status:200 OK
Strict-Transport-Security:max-age=31536000; includeSubDomains
Transfer-Encoding:chunked
X-Content-Type-Options:nosniff
X-Date:1417090658344
X-Robots-Tag:none
X-Runtime:0.066098
X-UA-Compatible:IE=Edge,chrome=1
X-XSS-Protection:1; mode=block
In the former case, I see an error message in the Network panel of my development tools that looks like this:
XMLHttpRequest cannot load
https://api.yammer.com/api/v1/groups.json?mine=1&&_=123456. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://my-access-origin.sharepoint.com' is
therefore not allowed access. The response had HTTP status code 429.
This doesn't make sense for a couple of reasons - first that the request is exactly the same in both cases and secondly that I am getting "429 Too Many Requests" as the status code, but with an explicit report that the Access-Control-Allow_origin header should be set. Which it never is in my requests, but it does appear to be on the successful responses.
Can anyone explain what is going on?
First make sure that you web url in Yammer registered app's "Javascript Origins"
if still the same issue then it could be:
This is related to Yammer rest API limit, more over to this 429 error
https://developer.yammer.com/restapi/
Please refer my answer on this post
XMLHttpRequest: Network Error 0x80070005, Access is denied
I used jQuery's .ajax function like:
$.ajax({
type:"POST",
url:"./index.php",
data:{ajax_fetch:1,action:"fetch_devInfo",nwType:nw_type,devTSN:dev_tsn,devSTime:dev_sTime,devETime:dev_eTime,dev_gType:dev_graphType},
dataType:"xml",
error:errHandler,
success:function(xml,textStatus)
{
xml_process(xml,textStatus,$("div#cont-Dev"),"Device");
}
});
// function for .ajax error callback
function errHandler(xhr, statusText, error)
{
if (xhr.status == "0" && statusText == "error")
{
$("body").append('<div class="ui-state-error ui-corner-all" id="error">Network down, try again later</div>');
}
else if (xhr.status == "200" && statusText == "parseerror")
{
window.location="./login.php";
}
}
My assumption is: if .ajax success, then the server must return it a XML file (identified by its header header("Content-type: text/xml")), that's why I specify the dataType as "xml"; however, if it failed (for example: session time out), index.php will redirect user to the login.php. In that case, the response is some HTML, shouldn't .ajax go to the function errHandler? Why does it always go to the success handler?
jQuery's $.ajax function takes the datatype and attempts to use the response as if it's that datatype, mostly to make things easier for you when you start using the response data. However, that's not how jQuery defines success or failure with the success or error handlers.
In this case, 'success' is defined by receiving information from the server. If information is received by the server, the request succeeded. Afterwards, jQuery tries to parse the information as XML (in your case). However, it isn't (or isn't what you expect), so it won't correctly do what you want it to.
Using that, I would rewrite the success handler to deal with XML or HTML data from the server, and use the error handler for your first error, where the server is down, etc.
I couldn't see a definitive answer in the jquery docs. But I'm thinking the data for the 302 response (or whatever) IS valid XML data (thus could be parsed) even if HTML isn't always.
HTTP/1.1 302 Found
Cache-Control: no-cache
Keep-Alive: timeout=3, max=993
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Expires: -1
Location: /Login.aspx
Server: Microsoft-IIS/7.0
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Fri, 11 Dec 2009 19:17:27 GMT
Content-Length: 139
<html><head><title>Object moved</title></head><body>
<h2>Object moved to here.</h2>
</body></html>
im currently setting up asp.net to accept DELETE http verb in the application.
However, when i send
"DELETE /posts/delete/1"
i always get a 405 Method not allow error. I tried to take a look at the header:
Response Headers
Cache-Control private
Pragma No-Cache
Allow GET, HEAD, OPTIONS, TRACE
Content-Type text/html; charset=utf-8
Server Microsoft-IIS/7.5, Private-Server
Date Tue, 17 Nov 2009 18:30:31 GMT
Content-Length 5590
Allow GET, HEAD, OPTIONS, TRACE
notice the Allow header in IIS7, it's only allow GET HEAD OPTIONS and TRACE. I currently using [AcceptVerbs(HttpVerbs.Delete)] in my delete controller (i think this one is extended by MVCContrib, correct me if im wrong)
PS: i send DELETE using Javascript:
function _ajax_request(url, data, callback, type, method) {
if (jQuery.isFunction(data)) {
callback = data;
data = {};
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
}
and:
_ajax_request($(this).attr('href'), "", function(d) { alert("submit"); }, "json", 'DELETE');
THank you in advance!
MVC 2 has this built in. You don't need MVCContrib for it. See HtmlHelper.HttpMethodOverride and HttpDelete.