I have been unable to successfully figure out why $.ajax refuses to connect to the Internet in Phonegap. The same code runs well in a standard HTML file. Access Origin is set to *.
Originally I thought Phonegap was refusing a connection to the Internet. However, it loads JQuery and JQuery Mobile remotely (by link tag). JQuery continues to return an error. Tested in JBoss Developer Studio (PG 4.1.2) and PG by commandline 4.3.
The error returned by stringifying the error object
error: {"readyStaate":4,"responseText":"{\n \"code\":
\"ENOTFOUND\",\n \"errno\":\"ENOTFOUND\",\n \"syscall\":\:getaddrinfo\"\n}","responseJSON":{"code":"ENOTFOUND","errno":"ENOTFOUND","syscall":"getaddrinfo"},"status":500,"statusText":"error"}
The Javscript used:
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('load', this.onDeviceLoad, false);
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceLoad: function() {
window.isAndroid = navigator.userAgent.match(/(android)/gi) != null;
},
onlineEvent: function() {
},
offlineEvent: function() {
},
onDeviceReady: function() {
app.receivedEvent('deviceready');
// online/offline must be set in onDeviceReady
document.addEventListener('online', this.onlineEvent , false);
document.addEventListener('offline', this.offlineEvent , false);
$.ajax({
method: "POST",
url: "http://www.someserver/server.php",
data: { name: "John", location: "Boston" }
})
.done(function( msg ) {
alert( "Data Saved: " + msg.posts );
console.log('NETWORK' + msg.posts);
})
.fail(function(error) {
alert("error: " + JSON.stringify(error));
});
},
receivedEvent: function(id) {
}
};
app.initialize();
Edit: I am aware of what the 500 error is. I have tested the server. It works fine with HTML5 and the same JQuery AJAX call. My hunch is that there is something with Phonegap; between the JQuery Client call and the server that is causing the error.
Edit2: The server name is private. The string is set to a real server on my actual code.
jQuery doesn't "connect to the internet". It's just a JavaScript library. The 500-status response you're getting is telling you that the server you're trying to POST to is erroring:
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_Server_Error
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Related
We use FileOpener2 plugin for cordova to open a downloaded .apk file from our servers. Recently, we found that Android 6.0 or higher devices are throwing an exception only on the file open process. We were able to trace this down to the cordova.js file, where the posted exception occurs. We have yet to find a cause or a fix, but have put a workaround in place. Any info would be amazing on this so we can maintain our in-app self updating process going on all Android devices.
Code (Working on Android <= 6.0):
// we need to access LocalFileSystem
window.requestFileSystem(LocalFileSystem.PERSISTENT, 5 * 1024 * 1024, function (fs) {
//Show user that download is occurring
$("#toast").dxToast({
message: "Downloading please wait..",
type: "warning",
visible: true,
displayTime: 20000
});
// we will save file in .. Download/OURAPPNAME.apk
var filePath = cordova.file.externalRootDirectory + '/Download/' + "OURAPPNAME.apk";
var fileTransfer = new FileTransfer();
var uri = encodeURI(appDownloadURL);
fileTransfer.download(uri, filePath, function (entry) {
//Show user that download is occurring/show user install is about to happen
$("#toast").dxToast({
message: "Download complete! Launching...",
type: "success",
visible: true,
displayTime: 2000
});
////Use pwlin's fileOpener2 plugin to let the system open the .apk
cordova.plugins.fileOpener2.open(
entry.toURL(),
'application/vnd.android.package-archive',
{
error: function (e) {
window.open(appDownloadURL, "_system");
},
success: function () { console.log('file opened successfully'); }
}
);
},
function (error) {
//Show user that download had an error
$("#toast").dxToast({
message: error.message,
type: "error",
displayTime: 5000
});
},
false);
})
Debugging Information:
THIS IS NOT OUR CODE, BUT APACHE/CORDOVA CODE
Problem File: cordova.js
function androidExec(success, fail, service, action, args) {
// argsJson - "["file:///storage/emulated/0/download/OURAPPNAME.apk","application/vnd.android.package-archive"]"
//callbackId - FileOpener21362683899
//action - open
//service FileOpener2
//bridgesecret - 1334209170
// msgs = "230 F09 FileOpener21362683899 sAttempt to invoke virtual method 'android.content.res.XmlResourceParser //android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference"
var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson);
// If argsJson was received by Java as null, try again with the PROMPT bridge mode.
// This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666.
if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "#Null arguments.") {
androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
androidExec(success, fail, service, action, args);
androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
} else if (msgs) {
messagesFromNative.push(msgs);
// Always process async to avoid exceptions messing up stack.
nextTick(processMessages);
}
I'm trying to build a simple application on cordova using aerogear push notification plugin
What i'm doing is following closely this guide: https://aerogear.org/docs/guides/aerogear-cordova/AerogearCordovaPush/#_sample_example
However, after put the sample code in my js, this line:
push.register(onNotification, successHandler, errorHandler, pushConfig);
will cause a reference error since push is not defined
I followed all the step before and the aerogear-cordova-push plugin is in the folder of the plugins, maybe i require some additional steps to refer to the plugin?
Also, the plugin provide an index.html as example inside its folder, but even using that i'm not able to resolve push
I tried to move the js files of the plugin in the www folder and linked them on index before the execution of index.js, since this it isn't very correct cause other reference errors
The index.html on the www folder is the same that a standard cordova project provide after its creation
This is my index.js, i'm able to show the error on android throught the try catch:
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() {
try {
app.receivedEvent('deviceready');
var pushConfig = {
pushServerURL: "...",
android: {
senderID: "...",
variantID: "...",
variantSecret: "..."
}
};
push.register(app.onNotification, successHandler, errorHandler, pushConfig);
}
catch (e){
alert(e);
}
function successHandler() {
console.log('success')
}
function errorHandler(message) {
console.log('error ' + message);
}
},
onNotification: function(event) {
alert(event.alert);
},
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}}; app.initialize();
I solved this because the plugin wasn't correct installed in my application, and the installation would fail because i was missing the google-service.json file that is required in order to build for android
I'm trying to automate end to end testing with protractor and I'm using sinonjs to setup a fakeServer to respond to certain ajax calls (not all) which are triggered by button clicks.
I'm stuck and not sure how to go about it and being a novice in automation I'm not sure if I'm on the right path.
var sinon = require('sinon');
describe("SinonFakeServerTest", function() {
var fakeServer;
beforeEach(function () {
fakeServer = sinon.fakeServer.create();
fakeServer.autoRespond = true;
var data = {key1: 'xyz', key2: 'abc'};
var response = [ 200, { "Content-Type": "application/json" }, data ];
fakeServer.respondWith( '/abc/xyz/*', response );
}
afterEach(function () {
fakeServer.restore();
}
it("should fake a ajax request", function () {
// click on this button triggers ajax call..
element(by.css('.take-button')).click();
//should show fake data on ui
});
});
This is the production code for button click controller and model
'.take-button click' : function(el, ev) {
model.getData(listParams, this.proxy('setUpData'));
},
getList : function(params, success) {
$.ajax({
url : '/abb/xyz/getAll.htm',
dataType : 'json',
type : "GET",
data : {
params : params
},
success : success
});
}
I didn't successfully fake server with Sinon's fakeServer feature when production code was using JQuery for AJAX calls.
I would suggest to try plain Sinon stubbing for $.ajax. There is actually example on sinonjs.org site (look into section Testing Ajax):
after(function () {
// When the test either fails or passes, restore the original
// jQuery ajax function (Sinon.JS also provides tools to help
// test frameworks automate clean-up like this)
jQuery.ajax.restore();
});
it("makes a GET request for todo items", function () {
sinon.stub(jQuery, "ajax");
getTodos(42, sinon.spy());
assert(jQuery.ajax.calledWithMatch({ url: "/todo/42/items" }));
});
I solved the above issue in protractor without sinonjs.
I used mockjax to hack selected ajax calls and injected this script through browser.executeScript()
I am trying to set up a basic example that sends a custom keen.io event via js. At the moment I do not need any presentation, visualisation, etc.
Here is the example that I created from another one I found online. I attempted several variations, and all of them work in Google Chrome, but none of them works in Firefox (38.0 for Ubuntu canonical - 1.0).
if I add to the head the inline script (!function(a,b){a("Keen"...) as it is proposed in the manual, I do not get any errors in FF, but it seems that addEvent never gets called and it produces no response, "err" nor "res".
if I include the library from the CDN (d26b395fwzu5fz.cloudfront.net/3.2.4/keen.min.js), I get an error when the page is loaded:
ReferenceError: Keen is not defined
var keenClient = new Keen({
If I download the js file and serve it locally, after the button is clicked, I get the following error response:
Error: Request failed
err = new Error(is_err ? res.body.message : 'Unknown error occurred');
All of these attempts work from Chrome, but I need this to work from other browsers too.
I received a response from keen.io team. It turned out that Adblock Plus is interfering with the script. After I disabled it everything works in FF as in Chrome.
After some investigation in turned out that request to http://api.keen.io was blocked by "EasyPrivacy" filter of ABP with these filter rules: keen.io^$third-party,domain=~keen.github.io|~keen.io
So, sending a request to an "in-between" server (a proxy) seems to be the only solution that I can see.
We have a bit specific use case - a need to track a static site and also an available access to a rails api server, but the solution we ended up using may come useful to someone.
error.html
<html>
<head>
<title>Error</title>
<script src="/js/vendor/jquery-1.11.2.min.js"></script>
<script src="/js/notification.js"></script>
<script type="text/javascript">
$(document).on('ready', function () {
try {
$.get(document.URL).complete(function (xhr, textStatus) {
var code = xhr.status;
if (code == 200) {
var codeFromPath = window.location.pathname.split('/').reverse()[0].split('.')[0];
if (['400', '403', '404', '405', '414', '416', '500', '501', '502', '503', '504'].indexOf(codeFromPath) > -1) {
code = codeFromPath;
}
}
Notification.send(code);
});
}
catch (error) {
Notification.send('error.html', error);
}
});
</script>
</head>
<body>
There was an error. Site Administrators were notified.
</body>
</html>
notification.js
var Notification = (function () {
var endpoint = 'http://my-rails-server-com/notice';
function send(type, jsData) {
try {
if (jsData == undefined) {
jsData = {};
}
$.post(endpoint, clientData(type, jsData));
}
catch (error) {
}
}
// private
function clientData(type, jsData) {
return {
data: {
type: type,
jsErrorData: jsData,
innerHeight: window.innerHeight,
innerWidth: window.innerWidth,
pageXOffset: window.pageXOffset,
pageYOffset: window.pageYOffset,
status: status,
navigator: {
appCodeName: navigator.appCodeName,
appName: navigator.appName,
appVersion: navigator.appVersion,
cookieEnabled: navigator.cookieEnabled,
language: navigator.language,
onLine: navigator.onLine,
platform: navigator.platform,
product: navigator.product,
userAgent: navigator.userAgent
},
history: {
length: history.length
},
document: {
documentMode: document.documentMode,
documentURI: document.documentURI,
domain: document.domain,
referrer: document.referrer,
title: document.title,
URL: document.URL
},
screen: {
width: screen.width,
height: screen.height,
availWidth: screen.availWidth,
availHeight: screen.availHeight,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth
},
location: {
hash: window.location.hash,
host: window.location.host,
hostname: window.location.hostname,
href: window.location.href,
origin: window.location.origin,
pathname: window.location.pathname,
port: window.location.port,
protocol: window.location.protocol,
search: window.location.search
}
}
}
}
return {
send: send
}
}());
example of sending notification manually from js code:
try {
// some code that may produce an error
}
catch (error) {
Notification.send('name of keen collection', error);
}
rails
# gemfile
gem 'keen'
#routes
resource :notice, only: :create
#controller
class NoticesController < ApplicationController
def create
# response to Keen.publish does not include an ID of the newly added notification, so we add an identifier
# that we can use later to easily track down the exact notification on keen
data = params['data'].merge('id' => Time.now.to_i)
Keen.publish(data['type'], data) unless dev?(data)
# we send part of the payload to a company chat, channel depends on wheter the origin of exception is in dev or production
ChatNotifier.notify(data, dev?(data)) unless data['type'] == '404'
render json: nil, status: :ok
end
private
def dev?(data)
%w(site local).include?(data['location']['origin'].split('.').last)
end
end
Question: How do you reconnect a client to the server after you have issued a manual .disconnect()?
In my current project, I need to disconnect a client from the server when the user log out from the session. I did a socket.disconnect() to do the disconnection successfully. Server removed the user from the session.
After awhile, the user decided to login again, but socket.io refuses to connect.
I am clear that Socket.IO has implemented reconnection algorithm but clearly this is a different case.
Below is the piece of code where I do the connection. On second trigger of this block of code, object socket was created, but no connect was fired from this object.
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier: hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
UPDATE: As requested by #Tony
In fact the whole thing is wrapped under Sencha Touch 2.0, but I believe there is nothing to do with ST2.0
This is my Data Class. Usage of this class is when the user logged in, this class will get initialized. And upon the user logout, the system will call the disconnect() method in this class.
When the user login again, this class is initialized again, but funny is the socket somehow retained all the previous events and sessions it has previously.
/**
* Serve as interface to wait for data communication in between server and client
*/
Ext.define('go.module.connect.Data', {
mixins: {
observable: 'Ext.mixin.Observable'
},
config: {
account: null
},
ready: false,
socket: null,
constructor: function(cfg) {
var me = this,
hashed_identifier = Sha1.hash(go.__identifier);
me.initConfig(cfg);
var account_id = me.getAccount().get('id');
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
console.log('connect');
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier:hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
console.log(socket);
if (!socket.socket.connected){
socket.socket.reconnect();
}
me.socket = socket;
me.callParent([cfg]);
},
disconnect: function() {
this.socket.disconnect();
this.socket.removeAllListeners();
this.socket.socket.removeAllListeners();
},
log: function(msg) {
console.log('## Connect: '+msg);
}
});
And below is my console.log results:
And below is my node.js debug window
I believe the root cause of this funny scenario is that the previously attached connect event listener is not removed thoroughly. How should I remove it? Should I use once? or I should specify the listener function as well. I thought removeAllListeners() is sufficient for this task.
The standard approach in latest socket.io is:
socket.on('disconnect', function() {
socket.socket.reconnect();
})
This is what I've been using in my app and works great. It also ensures that the socket keeps trying to reconnect if the server goes way, and eventually reconnects when the server is back online.
In your case, you need to ensure two things:
You create your socket only once. Don't call socket = io.connect(...) more than once.
You setup your event handling only once - otherwise they will be fired multiple times!
So when you want to reconnect the client, call socket.socket.reconnect(). You can also test this from the browser console in FireFox and Chrome.
You can reconnect by following client side config.
// for socket.io version 1.0
io.connect(SERVER_IP,{'forceNew':true };
I'm doing this way with socket.io 1.4.5 and it seems to work, for now:
var app = {
socket: null,
connect: function() {
// typical storing of reference to 'app' in this case
var self = this;
// reset the socket
// if it's not the first connect() call this will be triggered
// I hope this is enough to reset a socket
if( self.socket ) {
self.socket.disconnect();
delete self.socket;
self.socket = null;
}
// standard connectiong procedure
self.socket = io.connect( 'http://127.0.0.1:3000', { // adapt to your server
reconnection: true, // default setting at present
reconnectionDelay: 1000, // default setting at present
reconnectionDelayMax : 5000, // default setting at present
reconnectionAttempts: Infinity // default setting at present
} );
// just some debug output
self.socket.on( 'connect', function () {
console.log( 'connected to server' );
} );
// important, upon detection of disconnection,
// setup a reasonable timeout to reconnect
self.socket.on( 'disconnect', function () {
console.log( 'disconnected from server. trying to reconnect...' );
window.setTimeout( 'app.connect()', 5000 );
} );
}
} // var app
app.connect();
socket.socket.connect();
gets you reconnected.
It seems to me it is how you handle the disconnect...
Worked for me using socket.io - v1.1.0
wrong way...
var sock = io( '/' );
sock.on( 'connect', function(x) { console.log( 'Connected', x ); } );
// now we disconnect at some point:
sock.disconnect();
// now we try to reconnect...
sock.connect()
// or
sock.reconnect();
// - both seem to create the new connection in the debugger, all events are missing though
correct way...
// As above with 3 extra characters, everything functions as expected...
//events fire properly...
sock.io.disconnect();
// consequently i'm also using (for consitency)
sock.io.reconnect();
// sock.connect() still seems to work however.
socket.io v2.0 (current)
For the peoples that was looking as me for the last version please find the doc extract as below:
To manually reconnect:
socket.on('disconnect', () => {
socket.open();
});
socket.io-client v2.2.0
import io from "socket.io-client"
var socket = io(url) // initial connection
const reconnect = () => {
if(!socket.connected) {
socket = io(url) // reconnects to a new socket
}
}