I have to debug an Ajax Coldfusion8 application from a remote access point and am struggling to get anything to work.
The system works fine on my localhost but on the production server, I'm getting nowhere with nowhere being the page loads fine but all Ajax requests go into oblivion (commit error) without triggering a Coldfusion error.
My AJAX setup is as follows:
1). Setup
$(document).on( "click", '.su, .cu' , function() {
var form = $(this).closest('form'),
switcher = form.find('input[name="form_sub"]').val(),
service = "../serve/form_user.cfc",
method = "process",
returnformat = "JSON",
targetUrl = "",
formdata = form.serialize()+"&method="+method+"&returnformat="+returnformat,
successHandler = function() {
alert("hello")
};
ajaxFormSubmit( form, service, formdata, targetUrl, successHandler, "no" );
return false;
});
make AJAX call
var ajaxFormSubmit =
function ( form, service, formdata, targetUrl, successHandler, dataHandler ){
$.ajax({ async: false, type: "post",
url: service, data: formdata, dataType: "json",
success: function( objResponse ){
if (objResponse.SUCCESS){
alert("success!");
successHandler( objResponse )
}
})
}
Server Side
On the server side I have a "master-slave" cfc-setup. There are type-cfcs (user, whatever), which are extensions of a main form_switch like so:
Both files are mapped from application.cfc like so:
THIS.mappings["/controllers"] = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "controllers";
THIS.mappings["/serve"] = GetDirectoryFromPath( GetCurrentTemplatePath() ) & "services";
The type cfc extends to the form_switch
// user cfc
<cfcomponent extends="controllers.form_switch" output="false">
...
</cfcomponent>
The form_switch itself does all the basic stuff like validation and calling database commit in the type.cfc. Looks like this:
<cfcomponent output="false" hint="switchboard for form handling">
...
// function called by AJAX
<cffunction name="Process" access="remote" returntype="struct" output="false">
<cfset var LOCAL = {} />
<cfset LOCAL.Response = { Success = true, Errors = [], Data = "" } />
// set form data
<cfif IsStruct( ARGUMENTS[ 1 ] )>
<cfset THIS.SetFormData( ARGUMENTS[ 1 ] ) />
<cfelse>
<cfset THIS.SetFormData( ARGUMENTS ) />
</cfif>
// validate
<cfset LOCAL.Response.Errors = THIS.Validate() />
// commit
<cfif ArrayLen( LOCAL.Response.Errors )>
<cfset LOCAL.Response.Success = false />
<cfset LOCAL.Response.Errors = serializeJSON(LOCAL.Response.Errors)>
<cfelse>
<cftry>
<cfset LOCAL.Response = THIS.Commit() />
<cfcatch>
<cfset LOCAL.Response.Success = false />
<cfset LOCAL.Response.Errors = [["server_error","commit error"]] />
</cfcatch>
</cftry>
</cfif>
<cfreturn LOCAL.Response />
</cffunction>
</cfcomponent>
I'm clueless why it does not work and even worse I'm guessing blind why?
The ajax returns "commit error", so I'm reaching *form_switch* alright.
Question: How can I debug this?
I tried:
Dumping to screen > does not work as I'm using AJAX.
Dumping to file (I have the full path of the server and I can access the server, so I set up a dump.txt and tried
<cfdump output="F:\full\path\to_root\dump.txt" label="catch" var="hello">
but this gives me a 505 error email with
Diagnose: An error occurred when performing a file operation write on file F:\full\path\to_root\dump.txt
I can't use the CF admin AJAX debugging because I don't have access to the CFAdmin from remote.
What else can I do? Also, if someone knows what the problem might be... answers are also welcome... Must be something basic, like messed up mappings or not having some sort of user privilige on the server ...I assume?
THANKS!
And it's Coldfusion8 and MySql 5.0.88 .... with production being MySQL 5.5, but this is another issue I think.
EDIT:
Ok. I have to use e:\ and E:\ to write to dump.txt from application.cfc. But it still does not work from form_switch.
Have you tried calling your cfc method directly in the browser using url parameters instead of the post you would do from AJAX?
Stick a cfdump in the catch with a cfabort.
Call your cfc like this:
http://yourdomain.com/serve/forms users.cfc?method=process&arg1=qwe&arg2=963
This should either give you a result from your method or a dump of the error
Basic problem indeed....
E:\ != e:\
Related
In the CF 2016 Administrator page, by selecting the check box "Prefix serialized JSON with" //ABC (form example), it will break the function below, because it will add the string //ABC to the JSON
How can we remove the prefix //ABC before parsing the JSON, please?
<cffunction name="searchData" access="remote" returnformat="JSON">
<cfquery name="getData" datasource="#dataSource#">
SELECT *
FROM aTable
</cfquery>
<cfreturn serializeJSON(getData)>
</cffunction>
Thank you for your help
We have an option for this prefix Serialized JSON uncheck the Prefix serialized JSON with options in our admin comes under the options cfadmin - > Server Settings - > setting table you can see that options. FYR, Please refer my below images & sample codes,
Before uncheck the prefix option:
<cfset struct = {"name":"thiraviam", "age":24}>
<cfdump var="#serializeJSON(struct)#">
Output:
//abc{"name":"thiraviam","age":24}
After uncheck the prefix option:
<cfset struct = {"name":"thiraviam", "age":24}>
<cfdump var="#serializeJSON(struct)#">
Output:
{"name":"thiraviam","age":24}
[]
I hope it's help you more. Thank you !
You did not provide how you are calling this service. Regardless, all you need to do when calling a service which prefixes the JSON data is remove the prefixed data before processing the response. Below is an example using jQuery to make an AJAX call to such a service.
For jQuery AJAX the key for this is to use the dataFilter option. The dataFilter option gives you access to the raw response so it can be sanitized.
A function to be used to handle the raw response data of XMLHttpRequest. This is a pre-filtering function to sanitize the response. You should return the sanitized data. The function accepts two arguments: The raw data returned from the server and the 'dataType' parameter.
From the jQuery documentation
Here is an example. Notice how the dataFilter in this case is removing the first 2 characters from the response with this code; data.substr(2). For your example you would need to increase that to 5 in order to remove //ABC.
$.ajax({
type: 'POST',
cache: false,
data: {property1:'somevalue',property2:'someothervalue'},
dataFilter: function(data, type) {return data.substr(2)},
dataType: 'json',
url: 'https://www.somedomain.com/api/service/',
success: function(data, stat, resp) {
if(!data.error) {
// good return so do what you need to do
// this is assuming the service returns an 'error' field
// the JSON data is accessible by using data.fieldname format
} else {
// bad return so trap it
}
},
error: function(resp, stat, err) {
// service call failed so trap it
}
});
I want to sent push messages with Firebase Cloud Messaging. Everything is working, except for one thing. I want to save the response (see below) from Firebase to update a user profile in the database. So let's say the response gives back a failure, I want to sent that response back to my database.
To sent a push message I use this script:
var key = 'my-key';
var to = 'to-key';
var notification = {
'title': 'Portugal vs. Denmark',
'body': '5 to 1',
'icon': 'firebase-logo.png',
'click_action': 'http://localhost:8081'
};
fetch('https://fcm.googleapis.com/fcm/send', {
'method': 'POST',
'headers': {
'Authorization': 'key=' + key,
'Content-Type': 'application/json'
},
'body': JSON.stringify({
'notification': notification,
'to': to
})
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.error(error);
})
The response I get back from the Firebase is:
My question is how can I save (or sent) that response to my coldfusion server. I was thinking of re-writing the script to coldfusion like:
<cfscript>
objResponse = {
'message':{
'to':'SOME_TOKEN',
'notification':{
'title': 'Portugal vs. Denmark',
'body': '5 to 1',
'icon': 'firebase-logo.png',
'click_action': 'localhost:8081'
}
}
}
</cfscript>
<Cfdump var="#objResponse#" >
<cfoutput >#SerializeJSON(objResponse)#</cfoutput>
<cfhttp url="https://fcm.googleapis.com/fcm/send" method="post" result="objGet">
<cfhttpparam type="header" name="Accept" value="application/json" />
<cfhttpparam type="header" name="Authorization" value="key=MY_KEY">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
<cfhttpparam type="body" value='#SerializeJSON(objResponse)#'/>
</cfhttp>
But that is giving me a 400 bad request:
On https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream I found
Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields (for instance, passing a string where a number was expected). The exact failure reason is described in the response and the problem should be addressed before the request can be retried.
So I understand it has something to do with the JSON request i'm sending, but I can't figure out what the problem is.
Since you are making this request from javascript in your browser, you would need to add some code in the .then() callback that would make an ajax post request to your ColdFusion server, sending the data you want to save.
Not sure what your flow is here, but you could also make the http request from the ColdFusion server itself.
I am using ColdFusion 11. I inherited an application which uses the mm_wizard_login ColdFusion feature for their login functionality. Now I have to implement the change password functionality in this application. So if the user logs in and the application finds that this user is logging in for the first time, it should redirect the user to change their initial password.
So I decided to use a jQuery third party modal plugin.
I have added the jQuery plugin functionality in the mm_wizard_login.cfm page. During the authentication process, the scenario where the user needs to change password, the mm_wizard_authenticate.cfc denies the login and redirects them back to the mm_wizard_login.cfm page and then the plugin opens up and allows user to type in their new password. After the user clicks the submit, in jQuery I am intercepting their submit and I am making an AJAX call to another cfc which is accepting the new password and calling a SQL Server stored procedure to change their password. This cfc method returns JSON back to the AJAX call but the returning value is not JSON, it is returning the HTML for the mm_wizard_login.cfm page itself.
Everything is working, except the AJAX call which is expecting JSON.
In Chrome dev tools, I went into the network tab and under response tab, It is returning back the HTML for mm_wizard_login.cfm page. I don't understand this.
Here is my AJAX call below:
var refData = $.ajax({
url: 'testmethod.cfc',
method: 'POST',
dataType: 'json',
data:{
method:'ChangePassword', //Call the method
jsonData: JSON.stringify($(formdata).serializeArray())
}
})
.done (function (d) {
if (d.Result == 'OK')
$("#modal-custom").iziModal('#modal-custom','setTitle', d.message);
$("#modal-custom").iziModal('#modal-custom','close');
else{
changePwd_ErrorHandler(d.message);
}
})
.fail (function (XMLHttpRequest, textStatus, errorThrown) {
changePwd_ErrorHandler(textStatus + '. Please try again');
});
After nothing worked then I just tried a basic AJAX call from my mm_wizard_login.cfm page, here it is below:
var test = $.ajax({
url: 'testmethod.cfc',
method: 'POST',
dataType: 'json',
data:{
method:'MethodTest', //Call the method
}
})
.done (function (d) {
})
.fail (function (XMLHttpRequest, textStatus, errorThrown) {
alert('Unable to change password. Please try again');
});
This is not working either. It is returning the same thing. Not JSON but the HTML content of mm_wizard_login.cfm. Please help.
This is my test cfc function which is being called from the login page.
[Upate] My test cfc method:
<cffunction name="MethodTest" access="remote" output="true" returntype="string" returnformat="json" hint="Adds/Edits User Info .">
<cfset retJSON = '{"Result": "Error","message": "Action Failed", "TotalRecordCount":0}'>
<cfreturn retJSON>
</cffunction>
ColdFusion being as obscure as it is, Twilio doesn't have any SDKs for it. I'm trying to give Synch a go; I'm not getting the JSON request for the access token correct. Trying to mimic what is done by their node.js example here, I thought I could just output the JSON to the page on token.cfm:
{
"identity":"#Username#",
"token":["#AccountSID#","#APPSID#","#SECRET#"]
}
This is called from index.cfm:
<script src="js/jquery.js" ></script>
<script src="https://media.twiliocdn.com/sdk/js/sync/releases/0.5.7/twilio-sync.min.js"></script>
<script>
function fetchAccessToken(handler) {
// We use jQuery to make an Ajax request to our server to retrieve our
// Access Token
$.getJSON('token.cfm', function(data) {
// The data sent back from the server should contain a long string, which
// is the token you'll need to initialize the SDK. This string is in a format
// called JWT (JSON Web Token) - more at http://jwt.io
console.log(data.token);
// Since the starter app doesn't implement authentication, the server sends
// back a randomly generated username for the current client, which is how
// they will be identified while sending messages. If your app has a login
// system, you should use the e-mail address or username that uniquely identifies
// a user instead.
console.log(data.identity);
handler(data);
});
}
$(document).ready(function()
{
fetchAccessToken(initializeSync);
function initializeSync(tokenResponse) {
var syncClient = new Twilio.Sync.Client(tokenResponse.token);
// Use syncClient here
}
});
</script>
The response I receive is
{code: 400, message: "Unable to process JSON"}
code:
400
message:
"Unable to process JSON"
Can I accomplish this? Or, alternately, can the token be built by JavaScript alone?
Your JS is a very roundabout way of writing this:
$(function() {
$.get('token.cfm').done(function (response) {
var syncClient = new Twilio.Sync.Client(response.token);
// ... use syncClient here
});
});
but this still requires that the response is actually parseable as JSON.
If your CFM page just contains this:
<cfoutput>
{
"identity":"#Username#",
"token":["#AccountSID#","#APPSID#","#SECRET#"]
}
</cfoutput>
then this almost certainly produces syntactically wrong JSON. Don't do that.
JSON is to be produced from a data structure and a serialization function, that's no different in ColdFusion than in any other language.
<cfset AccountSID = "...">
<cfset APPSID = "...">
<cfset SECRET = "...">
<cfset tokenData = {
"identity" = Username,
"token" = [AccountSID, APPSID, SECRET]
}>
<cfcontent type="application/json"><cfoutput>#SerializeJSON(tokenData)#</cfoutput>
There are other, nicer ways of creating JSON responses, most prominently CF components with functions annotated with the "json" returnformat, but doing it manually like above is enough for a one-off.
I'm at a loss.
I'm posting to a Coldfusion8 cfc via Ajax and while it works fine on my local machine, on the live server I cannot call any function in this CFC or it's extended CFC.
I want to do this:
<cfset LOCAL.response = THIS.commit() />
If I dump:
<cfdump output="e:\path\to\dump.txt" label="catch" var="committing">
<cfdump output="e:\path\to\dump.txt" label="catch" var="#THIS#">
<cfset dickhead = THIS.Commit() >
<cfdump output="e:\path\to\dump.txt" label="catch" var="out">
I'm getting:
committing
****************************************************************
catch - component services.form_service_user
extends controllers.form_switch
Methods:
DEFAULTS
[function]
Arguments: none
ReturnType: struct
Roles:
Access: public
Output: false
DisplayName:
Description:
PROCESS
[function]
Arguments: none
ReturnType: struct
Roles:
Access: remote
Output: true
DisplayName:
Description:
COMMIT
[function]
Arguments: none
ReturnType: struct
Roles:
Access: public
Output: false
Description:
...
So the methods/functions are there. But I'm not getting to out. Also I have cleared out the commit function except for a lone return value and a dump. I'm neither getting the dump nor the return value.
QUESTION:
If I'm inside PROCESS, why can I not call COMMIT on the live server when it works fine on production? Is this some kind of caching or whatever setting? Also, I don't have access to the CFadmin, so I'm more or less guessing blind?
Thanks for any infos!
EDIT:
The commit call is inside a try/catch:
<cftry>
<cfdump output="e:\dump.txt" label="catch" var="a">
<cfdump output="e:\dump.txt" label="catch" var="#THIS#">
<cfset LOCAL.Response = THIS.Commit() >
<cfdump output="e:\dump.txt" label="catch" var="b">
<!--- COMMIT ERRORS --->
<cfcatch>
<cfdump output="e:\dump.txt" label="catch" var="ERROR">
<cfset LOCAL.Response.Success = false />
<cfset LOCAL.Response.Errors = [["server_error","commit error"]] />
</cfcatch>
</cftry>
I'm getting the "commit error" returned by AJAX
Check the access attribute on your methods.
If you are calling a method in a component (or inherited from a parent component) from another method in the same component, then access must be private, public or package. It cannot be remote.
Make sure your ColdFusion mappings are correct for the live server.
Make sure you have deployed all of the application files to the live server in the right location.