I have deployed a NodeJS web application up onto my DomainRacer hosting server. Everything has been setup and configured properly for the NodeJS application to make a GET request on the root path and render the home page properly.
Within this application, I have an email form in the "Contacts" section. This form contains a Google reCaptcha that I'd like to use for preventative measures against bots.
The way I have configured it, is that once I receive a value from the "g-recaptcha-response", I make a POST request via "fetch()" to my NodeJS backend to a specified path. I take the recaptcha response and save it as a variable, so that I can pass it into the Google site verify API link: https://www.google.com/recaptcha/api/siteverify?secret=[SECRET_KEY]&response=[RECAPTCHA_RESPONSE]
This is how it is currently setup in my NodeJS backend (SECRET_KEY and RECAPTCHA_RESPONSE being placeholders):
app.post('/contactEmail', async (req, res) => {
const email = req.body.email,
recaptcha = req.body.recaptcha,
site_key = [SECRET_KEY];
await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=[SECRET_KEY]&response=[RECAPTCHA_RESPONSE]`, {
method: 'GET',
})
.then(res => res.json()).then(async (data) => {
console.log(data['error-codes']);
if(data.success) {
var statusCode = await formatEmail(email);
res.json({statusCode : statusCode});
} else if(data['error-codes'][0] === 'invalid-input-response') {
res.json({statusCode: 300});
} else {
res.json({statusCode: 400});
}
})
.catch(err => {
console.log(err);
logError(err)
res.json({statusCode: 400});
})
})
Here is the script in my EJS file that handles the button click on the form to validate the information before making a POST request to "/contactEmail":
<script>
const form = document.querySelector('#email__form');
form.addEventListener('submit', (event) => {
event.preventDefault();
const recaptcha = document.querySelector('#g-recaptcha-response').value;
var emptyInputs = [],
inputs = [emailForm.querySelector('input'), emailForm.querySelector('textarea')];
inputs.forEach(i => {
if(i.value.length === 0) {
if(!emptyInputs.includes(i)) {
emptyInputs.push(i);
}
i.style.boxShadow = '2px 2px 2px rgb(100, 0, 0)';
} else {
if(emptyInputs.includes(i)) {
emptyInputs.pop(i);
}
i.style.boxShadow = 'none';
}
})
if(emptyInputs.length !== 0) {
alert('Please fill all fields in the form.');
} else {
fetch('/contactEmail', {
method: 'POST',
headers: {
'Content-type':'application/json'
},
body: JSON.stringify({email: inputs[0].value, message: inputs[1].value, recaptcha: recaptcha})
})
.then(res => res.json()).then(data => {
if(data.statusCode === 200) {
alert('Form was submitted!')
window.location = '/';
} else if (data.statusCode === 300) {
alert('Please complete reCaptcha');
} else {
alert('Error submitting form.');
}
console.log(data);
})
.catch(err => {
console.log(err);
})
}
})
</script>
The issue is that on the deployed site, I never receive a response back from "/contactEmail". However, this exact block of code works perfectly on my local machine. I am able to receive a response on my local machine.
In the deployed website, the POST request indefinitely states that it is "pending".
/contactEmail POST pending status
After a period of time passes, I then receive an internal server error 500 status code.
/contactEmail POST 500 status code response
Things that I have tried:
- attempted to find error logs inside cPanel, but cannot find a place to locate them. I've tried to setup a function to write the errors to a .log file in my backend, but since I never recieve a response from the POST request, nothing gets written to the .log file
- ensured that the domain that I am using is correctly spelled inside the settings of my reCaptcha setup
- tested the POST request in Postman, and received the same behavior from my website
- tried both reCaptcha V2 and reCaptcha V3 to check if there was a compatibility issue
- verified that both the Site Key and Secret Key are correctly spelled inside my code
- asked DomainRacer if there are any restricitions for POST requests and they have stated that there aren't any in place
- made sure that I received a token from the reCaptcha and it was passed along properly on my local environment, which it did
The reason I know the issue lies in the Google site verify URL fetch is because I've tested it by eliminating the fetch() request to the Google site verify link and just returning a temporary status code response. When I did this, the "/contactEmail" route actually returned a response on my deployed website and redirected back to the homepage.
I am wondering what the issue with this fetch() request to https://www.google.com/recaptcha/api/siteverify?secret=[SECRET_KEY]&response=[RECAPTCHA_RESPONSE] is?
I apologize if this question is still vague or not helpful as this is my very first question on this site.
UPDATE
After scouring the internet for hours, I've finally found the issue. Apparently the default fetch() is not backend friendly. It seems that I had to install the "isomorphic-fetch" package and use that as a substitute. After replacing the default fetch command with that new package, the request finally went through and I received a response.
I found the solution here: How to verify recaptcha in node js server call.
I am hoping others who are having this issue finds this helpful.