Empty response when responding to XMLHttpRequest() from Flask - javascript

I have a flask app that processes a post request from a javascript file using the XMLHttpRequest() object on the client side. Note this app is running on the localhost.
I am trying to return a response based on whether server raised an exception or not. The server processes the request fine but I can not access the response.
Here is the flask route on the server side.
#app.route("/updatecontact", methods=['POST', 'GET'])
def update_contact():
if request.method == 'POST':
try:
sqltools.update(request.json['msg'])
return "success"
except Exception as e:
return str(e), 400
And here is the function in javascript that sends the POST request and (is meant to) proccess the response back
function pushtodatabase(key, newvals) {
var xhttp = new XMLHttpRequest()
xhttp.open('POST', 'updatecontact', true);
var msg = {"msg": newvals.join("|")};
var msgjson = JSON.stringify(msg)
xhttp.setRequestHeader("Content-type", 'application/json;charset=UTF-8');
xhttp.send(msgjson);
console.log(xhttp.responseText);
console.log(xhttp.status);
}
Yet the status is 0 and the responseText empty
I've tried with different response types in flask. I've tried adding these headers
resp = Response("Foo bar baz")
resp.headers['Access-Control-Allow-Origin'] = '*'
resp.headers["Access-Control-Allow-Methods"] = "GET, POST, DELETE, PUT"
resp.status_code = 200
return resp
Any help would be greatly appreciated. Thanks.

You need to listen to load event of xhttp object and add the event handler for it. See Using XMLHttpRequest
E.g.
main.py:
from flask import Flask, request, render_template
app = Flask(__name__)
#app.route('/updatecontact', methods=['POST', 'GET'])
def update_contact():
if request.method == 'POST':
try:
return 'success'
except Exception as e:
return str(e), 400
else:
return render_template('updatecontact.html')
updatecontact.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>update contact</title>
</head>
<body></body>
<script>
function pushtodatabase(key, newvals) {
var xhttp = new XMLHttpRequest();
xhttp.open('POST', 'updatecontact', true);
var msg = { msg: newvals.join('|') };
var msgjson = JSON.stringify(msg);
xhttp.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
xhttp.send(msgjson);
xhttp.addEventListener('load', reqListener);
console.log('xhttp.responseText:', xhttp.responseText);
console.log('xhttp.status:', xhttp.status);
}
function reqListener() {
console.log('this.responseText:', this.responseText);
console.log('this.status:', this.status);
}
window.onload = function () {
pushtodatabase('key,', ['a', 'b']);
};
</script>
</html>
The output of the console.log:
xhttp.responseText:
xhttp.status: 0
this.responseText: success
this.status: 200

Related

Method not allowed on ajax request (keydown event active only while debugging)

I have a very strange problem with an AJAX request.
The server app.py
#### app.py
from flask import Flask, request, render_template
app = Flask(__name__)
app.debug = True
#app.route("/myajax", methods=['GET', 'POST'])
def mypostajaxreq():
print(request.form)
if request.method == "POST":
name = request.form["name"]
return " Hello " + name
else:
return "Just Hello"
#app.route("/")
def index():
return render_template("indexlistener.html")
if __name__ == "__main__":
app.run()
The indexlistener.html
<!DOCTYPE html>
<html>
<head>
<title>Practice AJAX</title>
<script type="text/javascript" src = "/static/js/myajaxrequestlistener.js"></script>
</head>
<body>
<form method="post">
<label>Name:<input type="text" id="name" value="" /></label>
<button type="button" id="btn-post">Click</button>
<div id="result"></div>
</form>
</body>
</html>
The myajaxrequestlistener.js file
function do_ajax ()
{
var req = new XMLHttpRequest();
var result = document.getElementById('result');
req.onreadystatechange = function()
{
if(this.readyState == 4 && this.status == 200) {
result.innerHTML = this.responseText;
}
}
req.open('POST', '/myajax', true);
req.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
req.send("name=" + document.getElementById('name').value);
};
document.addEventListener('DOMContentLoaded', function()
{
document.getElementById("btn-post").addEventListener("click", function()
{
do_ajax();
})
})
document.addEventListener('DOMContentLoaded', function()
{
document.addEventListener("keydown", function(event)
{
if(event.key === "Enter")
{
do_ajax();
}
})
})
This works all well when I click the button, as expected it fires the mypostajaxreq in the python code, however when I press Enter it returns Error 405. Method not allowed. It is unclear to me why it's happening, I checked with the debugger and I am entering the listener event to keydown, in fact, even weirder, the code works when I use the debugger but it doesn't when I press Enter directly. I suspect it's due to the listener but I don't understand why it shouldn't work. Besides I don't understand the logic of the error (405) I'm receiving: in my understanding this should happen only when the route on the server side doesn't accept the request method is called from, but here I accept both and besides I'm firing only POST requests from the webpage. I'm new to web programming, thanks in advance.
Pressing enter in the only textbox in a form will submit the form, sending a POST to / which is not an allowed method to that route.
You can attach a submit handler to the form instead of a keydown
Also, you don't have to use multiple DOMContentLoaded event handlers.
document.addEventListener('DOMContentLoaded', function()
{
document.querySelector('form').addEventListener("submit", function(event)
{
event.preventDefault();
do_ajax();
});
document.getElementById("btn-post").addEventListener("click", do_ajax);
});

Post custom HANDLER URL reCAPTCHA

I am trying to implement reCAPTCHA validation via Marketing Cloud - cloud page.
I have used this guide to do that: https://ampscript.xyz/how-tos/how-to-implement-google-recaptcha-on-marketing-cloud-forms/
What I want to do is to create a post request instead of use the action form property.
My Clint side script:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://www.google.com/recaptcha/api.js"></script>
</head>
<body>
<form id="form" >
<label>Email: </label>
<input type="email" name="EmailAddress">
<div
class="g-recaptcha"
data-sitekey="XXXXXXXXXXXXXXXXXXXXXX"
data-callback="grecaptchaCallback"
data-size="invisible"
></div>
<br>
<button>Send</button>
</form>
<script>
var form = document.getElementById('form');
form.addEventListener('submit', grecaptchaValidate);
function grecaptchaCallback() {
return new Promise(function (resolve, reject) {
if (grecaptcha.getResponse() !== '') {
var x=grecaptcha.getResponse();
console.log(x);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", "https://pub.s7.exacttarget.com/jnmlkgsfquv", true);
xhttp.setRequestHeader("Content-type", 'text/html',['Accept-Encoding'], ['identity'] );
xhttp.send();
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response=this.responseText;
console.log(response);
response=response.split("<script>");
console.log(response);
console.log(response[0].trim());
}
}
}
grecaptcha.reset();
})
}
function grecaptchaValidate(e) {
e.preventDefault();
grecaptcha.execute();
}
</script>
</body>
</html>
</script>
</body>
</html>
And this is my server-side script:
<script runat="server">
Platform.Load("core", "1.1.1");
try {
var g_recaptcha_response = Request.GetFormField("g-recaptcha-response");
var secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXX";
var payload = "secret=" + secret + "&response=" + g_recaptcha_response;
var contentType = "application/x-www-form-urlencoded";
var endpoint = "https://www.google.com/recaptcha/api/siteverify";
var req = HTTP.Post(endpoint, contentType, payload);
if (req.StatusCode == 200) {
var resp = Platform.Function.ParseJSON(String(req.Response));
if (!resp.success) throw "Wrong reCAPTCHA";
} else {
throw "reCAPTCHA API error";
}
/// DO SOMETHING
Write(Stringify(resp));
} catch (error) {
Write(Stringify({ status: "Error", message: error }));
}
</script>
The error I get when I send the request is:
{"status":"Error","message":"Wrong reCAPTCHA"}
<script>(function(a,m,i,g,o,s){o=a.createElement(g);s=a.getElementsByTagName(i)[0];o.src=m.origin+m.pathname+"/_t?eventType=CLOUDPAGESVISIT";o.width=0;o.height=0;o.style.display="none";s.appendChild(o);})(document,window.location,"body","img");</script>
<script src="https://7231513.collect.igodigital.com/collect.js"></script>
<script>
if (_etmc && typeof _etmc.push === 'function') {
_etmc.push(['setOrgId', '7231513']);
_etmc.push(['trackPageView']);
}
</script>
Another conclusion I came to- If I insert manually the value that I received from the client-side from x object (the grecaptcha.getResponse() )
The response correct:
{"success":true,"challenge_ts":"2020-07-29T09:30:03Z","hostname":"pub.s7.exacttarget.com"}
I would love to get an idea of how I create the request from the client-side to the server-side page according to post I am initiating?
Is there anything I'm missing? Or maybe I'm not working correctly?
Edit:
The problem was with the payload at server-side page, because the variable g_recaptcha_response was null.
My workaround is to catch the variable with query string variable:
%%[
set #x = RequestParameter("x")
]%%
<script runat="server">
Platform.Load("core", "1.1.1");
var x = Variable.GetValue("#x");
try {
// var g_recaptcha_response = Request.GetFormField("g-recaptcha-response");
var secret = "XXXXXXXXXXXXXXXXXXXXXXXXX";
var payload = "secret=" + secret + "&response=" + x;
var contentType = "application/x-www-form-urlencoded";
var endpoint = "https://www.google.com/recaptcha/api/siteverify";
var req = HTTP.Post(endpoint, contentType, payload);
if (req.StatusCode == 200) {
var resp = Platform.Function.ParseJSON(String(req.Response));
if (!resp.success) throw "Wrong reCAPTCHA";
} else {
throw "reCAPTCHA API error";
}
/// DO SOMETHING
Write(Stringify(resp));
} catch (error) {
Write(Stringify({ status: "Error", message: error }));
}
</script>
Because there is no way to catch URL data on SSJS I using AMPscript to catch x and pass it to payload, now I get a success response.
But I'm not sure if there have any security problem in this way.
First of all, you need to create your Cloud page using the Content Builder option. This will remove the script tags in your response.
Second, you are sending your data in the content type of text/html, try using application/x-www-form-urlencoded instead.
I believe, your Form Handler doesn't capture the g-recaptcha-response because it can't be retrieved with Request.GetFormField when you are sending text/html content type.
Please have a look at this article: https://ampscript.xyz/how-tos/perform-an-http-request/
Otherwise, use Axios for your client-side requests: https://github.com/axios/axios

Javascript output sent to PHP for adding into database

I have wrote a HTML/Javascript code generator but instead of outputting the code to a HTML site i would like the code to be send to php to be added to a database but i cant work out how to get the out put of the javascript into PHP
there is also another javascript doc to go with this if you need it to make it work ..
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<script src="../voucher_codes.js"></script>
</head>
<body>
<h1>pattern codes</h1>
<ul id="pattern-codes"></ul>
<script>
var patternCodes = voucher_codes.generate({
prefix: "BREAK-",
postfix: "-2019",
length:5,
count: 5,
charset: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
});
function fillList(listId, items) {
var list = document.getElementById(listId);
items.forEach(function(item) {
list.innerHTML += "<li>" + item + "</li>";
});
}
fillList("pattern-codes", patternCodes);
</script>
</body>
</html>
i am wanting the output of the function "fillList" to send the output to PHP if this is possible....
You would have to look into using AJAX or the Axios library to send requests to a server page such as PHP.
Here is a simple AJAX POST server request in Javascript:
`
<script>
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = this.responseText;
}
};
xhttp.open("POST", "request_page.php", true); // set method and page
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); // set content type that we are sending POST data
xhttp.send("key=VALUE&key=VALUE"); // POST values
}
</script>
`
On the PHP page if you want to give a response of data to use back in Javascript, make sure to
json_encode($array_values)
the data array before echoing it out and set the headers to
header("Content-Type: application/json")
so you can grab the response data in Javascript and it can be turned into a Javascript {Object} or [Array]

how to grab JSON Data from url using JavaScript? (new to JSON)

<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript - read JSON from URL</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
</head>
<body>
<script>
function setup() {
loadJSON("https://www.westelm.com/services/catalog/v4/category/shop/new/all-new/index.json", gotData, 'jsonp');
}
function gotData(data){
alert(data);
}
</script>
</body>
</html>
I am new to the developer role, please help. First it kept giving me Access denial to the url ERROR!. Then i learned about jsonp and added it. Now i don't see anything showing up, when i should be getting the json data. !JSON data from the url is correct ran it in JSONLINT!
var xmlhttp = new XMLHttpRequest();
var url = "https://www.westelm.com/services/catalog/v4/category/shop/new/all-new/index.json";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
That code will normally work, but for this you should be getting this error:
Failed to load
https://www.westelm.com/services/catalog/v4/category/shop/new/all-
new/index.json: No 'Access-Control-Allow-Origin' header is present on
the requested resource. Origin 'null' is therefore not allowed access.
The response had HTTP status code 403.
That's because this server doesn't allow JSON Reqs, and will not allow you access. You could try using CORS (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) but I'm not sure how much that will help you

How to set the Content-Type header using JavaScript

How can you set the Content-Type header to "application/x-www-form-urlencoded; charset=UTF-8" using JavaScript?
I need to do this so I can view a form with french characters without generating errors.
Thanks
Headers are set by the server delivering the content-type as part of the HTTP message. By the time it's in the browser and running the javascript it's too late. Do you have access to the server-side code? Why not set the content type to utf-8 in there? You can also do it as part of the meta tag in the head.
You can add a meta tag into the head of the page, or send the header server-side.
example,
<meta http-equiv="Content-type" content="application/x-www-form-urlencoded; charset=UTF-8"/>
on the server-side, say PHP:
<?php
header( 'Content-type: application/x-www-form-urlencoded; charset=UTF-8' );
?>
that's it!
The content type is set by the server before it sends the HTML to the browser. You can't modify it with JavaScript.
I assume that you want to communicate with the server, for example, to submit a form, and then the server sends you back the results, in which you need the correct Content-type to allow the server to communicate.
if so, then XMLHttpRequest.setRequestHeader() may help.
an example
(
() => {
const form = document.forms.namedItem("my-query-form")
form.addEventListener('submit', function (submitEvent) {
const outputElement = document.getElementById("msg")
const xhr = new XMLHttpRequest();
xhr.open("POST", "query", true);
xhr.setRequestHeader("Content-Type", "application/json"); // <----
xhr.onload = function (oEvent) {
if (xhr.status === 200) {
outputElement.innerHTML = `<p style="color:green;">${xhr.responseText}</p>`;
setTimeout(function () {
window.location.href = "/home";
}, 1000);
} else {
outputElement.innerHTML = `<p style="color:red;">Error ${xhr.status}: ${xhr.responseText}</p>`
}
};
const htmlFormControlsCollection = submitEvent.target.elements
const jsonData = JSON.stringify(
{
"username": htmlFormControlsCollection["username"].value,
});
xhr.send(jsonData);
submitEvent.preventDefault();
}, false);
}
)()

Categories