I need to use web sockets for some interactions with the user. I have pretty much copypasted solution from here - http://xsockets.net/blog/angular-js-xsocketsnet and got an issue with Firefox (27.0.1).
When I try to make this call (TwoWayBinding is my XSockets controller, I'm using .NET MVC on host side):
var connect = function (url) {
var deferred = $q.defer();
socket = new XSockets.WebSocket(url);
socket.on(XSockets.Events.open, function (conn) {
$rootScope.$apply(function () {
deferred.resolve(conn);
});
});
return deferred.promise;
};
connect("ws://localhost:49200/TwoWayBinding").then(function (ctx) {
isConnected = true;
queued.forEach(function (msg, i) {
publish(msg.t, msg.d);
});
queued = [];
});
I always get an error from Firebug:
Firefox can't establish a connection to the server at ws://localhost:49200/TwoWayBinding.
this.webSocket = new window.WebSocket(url, subprotocol || "XSocketsNET");
The same code works well in Chrome, it gets connected and I'm getting messages sent from host. Mentioned methods are wrapped into angular service, but this all works, I do not think this should be a problem.
One thing I was able to figure out from Fiddler was this:
Chrome:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
3 200 HTTP Tunnel to localhost:49200 0 chrome:3976
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
6 101 HTTP localhost:49200 /TwoWayBinding?XSocketsClientStorageGuid=5cf5c99aafd141d1b247ed70107659e0 0 chrome:3976
Firefox:
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1740 200 HTTP Tunnel to localhost:49200 0 firefox:1420
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1741 - HTTP localhost:49200 /TwoWayBinding -1 firefox:1420
Simply said - there is some additional parameter XSocketsClientStorageGuid in the response for Chrome which does not occur in the respose to FF. I'm not sure if that has any impact or if I'm completely wrong but will appreciate any advice if somebody experiences same issue.
Update:
It looks like the critical line is this one
socket = new XSockets.WebSocket(url);
as the socket is not created properly in Firefox. But I still not have the cause of this.
What version are you running on , did you make a new installation of XSockets.NET using the Nuget Package or did you use the git example mentioned in the quesion above?
I just did a test on FF 26.0 and 27.0.1 , and it did go well using this pice of example;
http://xsockets.github.io/XSockets.JavaScript.API/test/index.html
I will have a look at the old Angular example asap and makre sure it is fixed of there is a problem!
Kind regards
Magnus
Related
I have a server written with Nodejs that collects data. My client side is written with AngularJS. I need to create http request every two seconds to my server (setInterval) and display updated data. My server running 24/7. Can chrome block my requests if it reaches maximum? Can I implement another way, instead of create request from client side, maybe to push from my server?
Example of some request:
var indicesTimer = setInterval(getIndices,2000);
getIndices();
function getIndices(){
dataService.getIndices().then(function(res){
$scope.recentIndeces = res.data;
});
}
Check $interval service.
var stop = $interval(function() {
// Your code
}, 100);
With your code
var indicesTimer = $interval(getIndices,2000);
getIndices();
function getIndices(){
dataService.getIndices().then(function(res){
$scope.recentIndeces = res.data;
});
}
You can use websocket. By using that, your server can notify your client in case something changed in the server side so you don't have to do a polling (polling is what you do when sending request every x seconds). Take a look at socket.io
This is the typically behavior of a heartbeat. Chrome or any other browser does not block requests.
As long as your setInterval() handler doesn't run forever, it won't block other things from eventually running.
I have a spring webapp with spring security(3.2.3, so no CSRF protection) and angular.
In a controller i have a method like this one to update the users pw:
#RequestMapping("/accountinfo/password", method = arrayOf(RequestMethod.PUT))
#ResponseBody
#Secured("ROLE_USER")
open fun updateOwnPassword(user: User, #RequestBody password: String) {
val editedUser = user
editedUser.password = encoder.encode(password)
userRepository.save(editedUser)
}
The request is done via angular Service:
function changeOwnPassword(newPassword) {
return $http
.put('accountinfo/password', newPassword)
.then(function (response) {
return response.data
});
}
This works fine in every browser i tested with. Except if using IE 11.0.35 in a Citrix environment (Works outside of it,but can't see any specific configuration).
In that case i get 403 on the Request. When i change the method to POST it works fine again. I could do that for every function where i got this problem of course, but that doesn't seem like a clean solution.
As far as my research goes, i think it's something wrong with the way the browser writes the Request, but that's were i can't find out what to do.
EDIT:
I compared the request headers of both IE 11.0.35 inside and outside of Citrix and they seem exactly the same. The only difference is that the working version uses DNT=1 and the non-working version as WOW64 in the User-Agent attributes?
UPDATE:
I found out that it happens with DELETE too
Found the problem: The client sends the Requests through an additional Proxy that doesn't like PUT and DELETE and just cuts the session cookies off of it. We are adressing that problem with putting the tokens in the header in the future.
I'm writing an application that connects to a sails server.
This application is written with cordova, angularJS and Ionic.
When I launch my application in my browser (with ionic serve) the socket fails to connect to the server. Here is the message I get:
GET http://localhost:8100/socket.io/?__sails_io_sdk_version=0.11.0&__sails_io_s…sails_io_sdk_language=javascript&EIO=3&transport=polling&t=1443472067762-4 404 (Not Found)
The server is running locally on port 1337. I tried to change the above URL to:
http://localhost:1337/socket.io/?__sails_io_sdk_version=0.11.0&__sails_io_s…sails_io_sdk_language=javascript&EIO=3&transport=polling&t=1443472067762-4
and it's working.
In my code I set the URL after sails.io.js has been included:
io.sails.url = 'http://localhost:1337';
io.sails.useCORSRouteToGetCookie = false;
Why is it asking to localhost:8100 and not localhost:1337?
When I launch this application in my mobile device (setting the url to http://192.168.1.10:1337) it's working correctly.
Version of sails.io.js is 0.11.6, and version of sails is 0.11.0
localhost:8100 wont work in your mobile development environment. I faced same issue and changing localhost to your workstation's ip solved the problem
I finally found the solution (but I'm sorry I can't recall where I found it :()
The problem was that the io.sails.url = 'http://localhost:1337'; was executed after the first JS cycle, and thus the sails socket was already loaded. (that's (from what I understood) because in some browsers if the code is in another script tag it is executed in another cycle)
To make it work I had to add this code before I include the sails socket script:
var apiHost = 'localhost';
(function (){
var io;
Object.defineProperty(window, 'io', {
get: function (){
return io;
},
set: function (value){
var sails;
io = value;
Object.defineProperty(io, 'sails', {
get: function (){
return sails;
},
set: function (value){
sails = value;
sails.url = 'http://'+apiHost+':1337';
sails.useCORSRouteToGetCookie = false;
}
});
}
});
})();
In my GAE app (Python) I have implemented multitenancy and multi-site support based on the host part of the request object.
For example, www.foo.com/index.html and www.bar.com/index.html are both handled by the same app (e.g. myapp.appspot.com). The app reads the host-value and then decides which namespace and site-configuration to use. This works great as long as the app receives the request directly from the user-agent.
However, I would like to use the Channel API, but there is an issue because requests to /_ah/channel/connected/ and /_ah/channel/disconnected/ are not originating from the original user-agent. Instead, the request has Host: myapp.appspot.com and the parameter to=myapp.appspot.com. (The from parameter is the token I expect. Also www.foo.com/_ah/channel/jsapi is redirected to a talkgadget server which is not documented but seems to be as expected.)
I assume, the problem is caused by the code in channel.js which doesn't call my app using the original host, e.g. www.foo.com/_ah/channel/connected. Instead it uses a talkgadget.google.com host which (as far as I can tell) will then call my app, but using myapp.appspot.com, ignoring the original host and so I cannot use the request's host value for my purpose.
As a workaround, I can figure out a way of including the host information into the channel token, so when my connected and disconnected handlers receive the token, they can use the token instead.
However, I would like to know if there is a better approach, where I could still get the original host name (e.g. www.foo.com) requests to /_ah/channel/connected/ and /_ah/channel/disconnected/. Any ideas?
This is what I have tried so far (with-out any success):
Adding the custom domain host name to the JS src attribute:
<script type="text/javascript" src="//www.foo.com/_ah/channel/jsapi"></script>
I also tried to manually override the base-url of the channel socket, suggested here: https://stackoverflow.com/questions/16558776/google-app-engine-channel-api-same-origin-policy
<script type="text/javascript">
onOpened = function() {
// TODO
};
onMessage = function() {
// TODO
};
onError = function() {
// TODO
};
onClose = function() {
// TODO
};
goog.appengine.Socket.BASE_URL = "https://www.foo.com/_ah/channel/";
channel = new goog.appengine.Channel('{{channelToken}}');
socket = channel.open();
socket.onopen = onOpened;
socket.onmessage = onMessage;
socket.onerror = onError;
socket.onclose = onClose;
</script>
I couldn't find any official documentation for channel.js and I don't want to implement something that is going to break easily with the next update by Google.
Short of a proxy, I don't see a better way than including the information in-band. The problem is that the library/infrastructure (can't be certain without looking deeper) is stripping the HTTP-layer information (the Host header), and indeed you don't have any control of the HTTP layer to pass custom headers, etc. So, you either need to have the info at a lower layer (TCP doesn't even provide a means to do this, and since the entrypoint of your code is through the browser running channel.js, rather than a system-level process running on the bare network interface, this is out of the picture decisively), or at a higher layer, ie. within the channel.
I am calling an authentication service where I do a $http.post which returns a 303 resonse, redirecting to a get call returning the response.
When I make the post call using Postman, I get the desired response but when I do an angular $http.post call, it returns me a 401 error (which is user not authorized)
Am I missing something while making the angular call? The backend service seems to work fine as it works fine on Postman.
This is how the $http call looks:
$http.post(url, userData).success(function(data, status) {
//handle success
}.error(function(data, status) {
//handle error
});
The url and the user data is constructed absolutely fine in this case.
The reason that you get a GET call is that the browser handle the 303 response before the angular can reach that. And the handling sequence is first go to the browser and then go to the angular framework.
So briefly what happens is : you make call to the server --> the server return the 303 response -> your browser handle the 303 and make a request to some url (should be 'location' in the response header) --> the server receive the request and return the 401 authorized response --> again the browser receive the 401 response first but this time the browser redirect the response to the angular --> at last you can receive the data and status inside the error().
The solution for this could be switching to other response status code like 2xx, and you can get the location from the body. Then you can do the redirection manually. If you HAVE to use 303 or other 3xx as the response code I don't think there's any effective solution at this moment because you can't do much to the browser. As far as I know there might be a solution at browser level but don't know when that will happen.
Hope this can help anyone has the similar issue like this although it has been nearly one year since this issue raised.
Some other ref: https://groups.google.com/forum/#!topic/angular/GKkdipdMbdo
There's similar solution you can see from the link above.
I faced this issue and I found a redirect url in error object after lots of hours struggle.
loginWithLinkedIn() {
let data = {
// some kind of information here
}
return this.http.get(`https://www.someurl.com/oauth/v2/authorization`).subscribe(res => {
console.log(res)
}, err => {
console.log(err.url) // here is the redirect url
window.location.href = err.url
})
}
Note: when you make a request and you get 303 response which is considered as error, that's why we think we are getting error but error contains useful info.