React and NextJS: How can i detect the Location of my Client? - javascript

I have created a Website using NextJS and React. I want to provide the Website in several languages. To achieve this, I wanted to create in the page folder, subfolders, for example for the English language /en, for the German language, /de etc.
When a visitor then opens my Website, the correct subfolder is selected based on the public IP:
Example:
Request comes from America : the /pages/en folder is selected,
The request comes from Germany : the /pages/de folder is selected etc.
How can I do that? Since I have little experience in NodeJS environments, please show me concrete examples, many thanks...
I already have a server.js file. Maybe I can use this yes for it too...
const express = require('express')
const next = require('next')
const bodyParser = require('body-parser')
const request = require('request')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = express()
//parse application
server.use(bodyParser.urlencoded({ extended: false }))
//parse application/json
server.use(bodyParser.json())
server.post('/', (req, res) => {
addEmailToMailChimp(req.body.email, (error, response, body) => {
// This is the callback function which is passed to `addEmailToMailChimp`
console.log(response);
try {
var respObj = {}; //Initial response object
if (response.statusCode === 200) {
respObj = { success: `Subscribed using ${req.body.email}!`, message: response.body };
} else {
respObj = { error: `Error trying to subscribe ${req.body.email}. Please try again.`, message: response.body };
}
res.send(respObj);
} catch (err) {
var respErrorObj = { error: 'There was an error with your request', message: err.message };
res.send(respErrorObj);
}
});
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})

Use Next.js Internationalized Routing feature.
For Sub-path Routing
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
For Domain Routing:
// next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL', 'nl-BE'],
defaultLocale: 'en-US',
domains: [
{
// Note: subdomains must be included in the domain value to be matched
// e.g. www.example.com should be used if that is the expected hostname
domain: 'example.com',
defaultLocale: 'en-US',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.nl',
defaultLocale: 'nl-NL',
// specify other locales that should be redirected
// to this domain
locales: ['nl-BE'],
},
],
},
}
Follow https://nextjs.org/docs/advanced-features/i18n-routing for more details.

Related

i try to upload file in my mocha nodejs test but i got [Object null prototype] { file: { ... }}

i find evrywhere solution white :
app.use(bodyParser.urlencoded({extended: true}));
i can use
JSON.stringify(req.files)
but im sur having a way to fix my problem
my mocha test :
it('a file', async function () {
const body = { pseudo: 'user', password: 'test#123', mail: 'supermail' };
const response = await fetch(hostName + '/authentication/register', {
method: 'post',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
})
const usr = await response.json();
request.post('/usrAction1/doc')
.field('token', usr.token)
.attach('file', 'test/test.pdf')
.end(function (err, res) {
if (err) {
console.log(err)
}
console.log(res.status) // 'success' status
});
});
and my rout handler :
router.post('/doc', async (req, res) => {
console.log('req.files');
console.log(req.files)
})
also my server.js:
import express from 'express'
import authentication from './src/login.js'
import './global/host.js'
import bodyParser from 'body-parser'
import cors from "cors"
import verifyToken from './middleware/auth.js'
import { userAction1, userAction2 } from './src/userAction.js'
import verifyLevel from './middleware/level.js'
import fileUpload from 'express-fileupload';
export default function myApp() {
const whitelist = [/http:\/\/localhost:*/, /http:\/\/127.0.0.1:*/]
const corsConfig = { origin: whitelist }
const app = express();
const port = hostPort;
//json encoded
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.use(cors(corsConfig))
// enable files upload
app.use(fileUpload({
createParentPath: true
}));
app.use('/usrAction1', userAction1())
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
return app;
}
myApp();
but don't to work for me .
i also test white external client server who juste runing a form and send it to my tested adress and
do the same [Object null prototype]
thank u for evry litel help
i waiting of some help i using this magique code i found somwhere on stackoverflow:
req.files && Object.keys(req.files)?.map((obj, idx) => { console.log(req.files['file'].data) })
if somone have a better idea i waiting .
thank to all

In node.js, the post method is connected to get and a 404 error appears

node.js, if you change the 'post' method to 'get' in the client, it works well, but 404 error appears only in the 'post' method. May I know why?
P.S Many people say the problem is caused by the failure to find the path '/api/insert/' on the server, but I don't think it's because it works well when you change to the 'get' method.
client code
const writePost = async () => {
axios.defaults.withCredentials = true;
const config = {
headers: {
withCredentials: true,
},
body: {
title: writeData.title,
content: writeData.content,
register: writeData.register,
},
};
try {
//Successful response
await axios
.post("http://localhost:8000/api/insert", config)
.then((res) => {
console.log(res);
console.log(res.config);
});
} catch (error) {
//Failed to respond
console.log("write error", error);
}
};
node code
const cors = require("cors");
const express = require("express");
const app = express();
const mysql = require("mysql");
const PORT = process.env.port || 8000;
const bodyParser = require("body-parser");
const db = mysql.createPool({
host: "",
user: "",
password: "",
database: "",
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors({ credentials: true, origin: true }));
app.post("/api/insert", (req, res) => {
var title = req.body.title;
var content = req.body.content;
var register = req.body.register;
const sqlQuery =
"INSERT INTO BOARD (BOARD_TITLE, BOARD_CONTENT, REGISTER_ID) VALUES (?,?,?);";
db.query(sqlQuery, [title, content, register], (err, result) => {
res.send(result);
});
});
I recreated your setup exactly (as described, adding writeData varible in client code, and app.listen(PORT) in server.js) and worked for me, the most possible cause is PORT is being defined to something else than 8000, it checks for process.env.port before hand, removing that fixes it.
Basically, if you enter the url path in your browser, it displays the 'get' method, so it is one-sided for the error to appear. To test the 'post' method, use the 'form' tag 'method' 'post', or the 'controller get post' or 'postman'.

Post request not working on plesk while working on localhost

What I'm trying to do:
I'm trying to make a api that saves images. I'd send a post request to the api with the image in body and it saves to the static folder 'public/images'.
Problem: I tried to do this on localhost and it works perfectly. I've got the cross-origin error's before but I've fixed them. After I hosted the api on plesk, it doesn't save the image, or send a error message back. I've checked the logs on plesk and it says that it received the post request. but it's not doing anything with it.
front-end code on client-side (hosted on plesk):
const formData = new FormData();
var fileField = document.querySelector('input[type="file"]');
formData.append('image', fileField.files[0]);
const result = await fetch('https://cdn.dhulun.com/upload25single', {
method: 'POST',
body: formData
}).then(res => res.json())
if (result.status === "ok") {
console.log("Success");
window.location.href = '/';
} else if (result.status === "error") {
console.log("error", result.error)
} else {
console.log("Something went wrong...")
}
back-end code on api (hosted on plesk):
const express = require('express');
const multer = require('multer');
const path = require('path');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const cors = require('cors')
dotenv.config();
// CONNECT TO DATABASE
async function connectDB() {
await mongoose.connect(process.env.DB_CONNECT,
{ useNewUrlParser: true, useUnifiedTopology: true },
() => {
console.log("Connected to Portal Base [Server]")
});
}
connectDB();
var Media = require('./models/media')
// INIT APP
const app = express();
app.use(cors())
// STATIC FILES
app.use(express.static(__dirname + '/public'));
app.use('/image', express.static('./public/images'))
// RULES
// INIT MULTER
// Storage Engine
const storage = multer.diskStorage({
destination: './public/images',
filename: (req, file, cb) => {
return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`)
}
})
const upload = multer({
storage: storage,
limits: { fileSize: 8000000 },
})
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
});
app.post('/upload25single', upload.single('image'), async(req, res) => {
var image_url = `http://localhost:2525/image/${req.file.filename}`;
console.log({
status: 'ok',
image_url: image_url,
})
res.json({
status: 'ok',
image_url: image_url,
});
/* var location = req.body.location;
var category = req.body.category;
var sourceby = req.body.sourceby;
var tags = req.body.tags;
const media = new Media({
url: image_url,
location: location,
category: category,
source_by: sourceby,
tags: tags
});
try {
const saved = await media.saved();
res.json({
status: 'ok',
image_url: image_url,
});
} catch (error) {
res.json({
status: 'error',
err: error,
});
}
*/
})
function errHandler(err, req, res, next) {
if (err instanceof multer.MulterError) {
res.json({
status: 'error',
err: err.message
})
}
}
// ERROR HANDLING
app.use(errHandler)
app.listen(process.env.PORT || 2525, () => console.log("Server Started..."));
I get this error on the browser console (hosted on plesk): Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
When i click the code line number in the log i got sent to this line:
console.log("Something went wrong...")
EDIT: I got suggested to turn res.json() to res.text() and i got this:
<p>iisnode encountered an error when processing the request.</p><pre style="background-color: eeeeee">HRESULT: 0x6d
HTTP status: 500
HTTP subStatus: 1013
HTTP reason: Internal Server Error</pre><p>You are receiving this HTTP 200 response because <a href=https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config>system.webServer/iisnode/#devErrorsEnabled</a> configuration setting is 'true'.</p><p>In addition to the log of stdout and stderr of the node.exe process, consider using <a href=http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html>debugging</a> and <a href=http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html>ETW traces</a> to further diagnose the problem.</p><p>The last 64k of the output generated by the node.exe process to stderr is shown below:</p><pre style="background-color: eeeeee">(node:7696) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
Using Node.Js: Express & Multer

React.js, Express.js and the dreaded CORS

I'm sorry to be posting yet another question about CORS but I just can't figure this one out.
I have a React app using an Express.js server (running on http://localhost:9001) to upload an image to a Google Cloud storage bucket. I keep getting a CORS error even though the image is uploaded successfully and this is preventing me from getting the image's URL returned. I don't really understand how I can get a CORS error even though the image is uploaded but that's what's happening.
I have configured CORS on the Google Cloud storage bucket as follows:
[
{
"origin": ["http://localhost:3000"],
"responseHeader": "*",
"method": ["POST"],
"maxAgeSeconds": 3600
}
]
When I inspect the CORS error I'm getting I see the following:
The origin is http://localhost:3000, so that's configured correctly and I'm using POST to upload the image so that should be allowed as well.
The function I've written to upload the image is as follows:
function postImage(file) {
const formData = new FormData();
formData.append('file', file);
fetch(`${window.location.protocol}//${window.location.hostname}:9001/uploads`, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
// headers: {
// 'Content-Type': 'multipart/form-data'
// },
body: formData
})
// .then((response) => response.json())
.then((response) => console.log('This is your data:', response.data))
.catch(error => {
console.error('There has been a problem uploading your image', error);
});
}
I've commented out the headers as including them kept throwing up a Multipart: Boundary not found error that I've seen others have an issue with and removing the headers setting hasn't caused any other issues.
I have a helper function on the Express server that uploads the image to the Google Cloud storage bucket:
const uploadImage = (file) => new Promise((resolve, reject) => {
const { originalname, buffer } = file
const blob = bucket.file(originalname.replace(/ /g, "_"))
const filetype = blob.name.split('.').pop()
const filename = `${uuidv4()}.${filetype}`
const blobStream = blob.createWriteStream({
resumable: false
})
blobStream.on('finish', () => {
const publicUrl = format(
`https://storage.googleapis.com/${bucket.name}/${filename}`
)
resolve(publicUrl)
})
.on('error', () => {
reject(`Unable to upload image, something went wrong`)
})
.end(buffer)
})
Here are the functions on my Express server:
import { typeDefs } from './graphql-schema'
import { ApolloServer } from 'apollo-server-express'
import express from 'express'
import neo4j from 'neo4j-driver'
import { makeAugmentedSchema } from 'neo4j-graphql-js'
import dotenv from 'dotenv'
import { initializeDatabase } from './initialize'
const bodyParser = require('body-parser')
const multer = require('multer')
const uploadImage = require('./helpers/helpers')
dotenv.config()
const app = express()
const schema = makeAugmentedSchema({
typeDefs,
config: {
query: {
exclude: ['RatingCount'],
},
mutation: {
exclude: ['RatingCount'],
},
},
})
const driver = neo4j.driver(
process.env.NEO4J_URI,
neo4j.auth.basic(
process.env.NEO4J_USER,
process.env.NEO4J_PASSWORD
),
{
encrypted: process.env.NEO4J_ENCRYPTED ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF',
}
)
const init = async (driver) => {
await initializeDatabase(driver)
}
init(driver)
const server = new ApolloServer({
context: { driver, neo4jDatabase: process.env.NEO4J_DATABASE },
schema: schema,
introspection: true,
playground: true,
})
// Specify host, port and path for GraphQL endpoint
const port = process.env.GRAPHQL_SERVER_PORT || 4001
const path = process.env.GRAPHQL_SERVER_PATH || '/graphql'
const host = process.env.GRAPHQL_SERVER_HOST || '0.0.0.0'
// Code for uploading files to Google Cloud
app.use((req, res, next, err) => {
console.error(err.stack)
res.header("Access-Control-Allow-Origin", "*");
res.type('multipart/form-data')
res.status(500).json({
error: err,
message: 'Internal server error!',
})
next()
})
const multerMid = multer({
storage: multer.memoryStorage(),
limits: {
// no larger than 5mb.
fileSize: 5 * 1024 * 1024,
},
})
app.disable('x-powered-by')
app.use(multerMid.single('file'))
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
app.post('/uploads', async (req, res, next) => {
try {
const myFile = req.file
const imageUrl = await uploadImage(myFile)
res
.status(200)
.json({
message: "Upload was successful",
data: imageUrl
})
} catch (error) {
next(error)
}
})
server.applyMiddleware({ app, path })
app.listen({ host, port, path }, () => {
console.log(`GraphQL server ready at http://${host}:${port}${path}`)
})
app.listen(9001, () => {
console.log('Node.js -> GCP server now listening for requests!')
})
I've tried a lot of different things to get this working:
I've tried adding http://localhost:9001 to the CORS configuration, as well as other URLs
I've tried opening up all origins with "*" for
I've read through all the documentation [here][3]
I've tried following all the troubleshooting documentation Google has here
I've cleared my browser cache as I've seen that can cause the CORS errors to persist - see another post here
I've tried waiting over night for my Google Cloud CORS configuration to take effect as I've heard the configuration can take a bit of time to propagate
Despite all of this I'm still getting the CORS error but my upload is still working. I just need to clear the error so I can get the returned image URL.
You add cors to Google Cloud storage bucket but you forgot to add it to express server POST function. Or use it as global on your express server.
Try this on your express POST function:
res.header("Access-Control-Allow-Origin", "http://example.com");
Or
res.header("Access-Control-Allow-Origin", "*");
Or even better:
/* Headers */
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

Nodemailer not working on Heroku deployment

So I deployed my website portfolio with Heroku but my contact form (which uses nodemailer) is not working. It's weird because when I try it from my computer, I receive an email but I hear from others that it is not working on their end. This is the code of my index.js:
var express = require('express');
var router = express.Router();
var nodemailer = require('nodemailer');
var cors = require('cors');
const creds = require('./config');
var transport = {
host: 'smtp.gmail.com',
port: 465,
auth: {
user: creds.USER,
pass: creds.PASS
}
}
var transporter = nodemailer.createTransport(transport)
transporter.verify((error, success) => {
if (error) {
console.log(error);
} else {
console.log('Server is ready to take messages');
}
});
router.post('/send', (req, res, next) => {
var name = req.body.name
var email = req.body.email
var message = req.body.message
var content = ` name: ${name} \n email: ${email} \n message: ${message} `
var mail = {
from: name,
to: 'js5360#columbia.edu',
subject: 'New Message from Contact Form',
text: content
}
transporter.sendMail(mail, (err, data) => {
if (err) {
res.json({
status: 'fail'
})
} else {
res.json({
status: 'success'
})
}
})
})
const app = express()
app.use(cors())
app.use(express.json())
app.use('/', router)
app.listen(3002)
Here's the handler function I used:
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
message: "",
}
}
handleSubmit(e){
e.preventDefault();
axios({
method: "POST",
url:"http://localhost:3002/send",
data: this.state
}).then((response)=>{
if (response.data.status === 'success'){
alert("Message Sent.");
this.resetForm()
}else if(response.data.status === 'fail'){
alert("Message failed to send.")
}
})
}
resetForm(){
this.setState({name: "", email: "", message: ""})
}
Previously when I was working on localhost, I had already enabled access to less secure apps so it was working fine locally.
Admittingly, I don't know much about express or nodemailer and followed the instructions outlined here: https://blog.mailtrap.io/react-contact-form/. I have a feeling that the url I am sending get/post requests is a local one, which makes prevents it from working on computers other than my own.
Could anyone provide some input into what I have to fix? Any help would be greatly appreciated:)
Try this,
https://accounts.google.com/b/0/DisplayUnlockCaptcha
I received an email by Google that my account was being accessed from the server location, if you do just tell Google not to block it.
This will allow machines to access your Gmail remotely.
Note:This will work for a short period of time.
I'm actually having this same issue right now but there are a few things that you might need to fix prior to getting to that point, the big one is environment variables.
Is your page deploying to heroku still despite being served on port 3002? Like your content is showing up after Heroku builds it? I had that error and if you're facing it you can solve it by replacing server port with process.env.PORT, which heroku automatically will assign internally during produciton. See the server file I've pasted below.
const port = process.env.PORT || 3000;
...
app.listen(port, () => {
console.log(`Server is up on port ${port}!`);
});
will take care of that.
Secondly, the when deployed the URL isn't going to be localhost anymore. it has to point to your domain suffixed by the api route axios.post('www.example.com/send', object)...
you can have that taken care of during the build by using dotenv environment variables ex:
let URI = process.env.NODE_ENV === 'development' ? process.env.REACT_APP_DEV_URI : process.env.REACT_APP_PROD_URI;
and having a .env file in your root directory
REACT_APP_DEV_URI=http://www.localhost:3000
REACT_APP_PROD_URI=https://www.example.com
then in your react client
axios.post(`${URI}/send-email`, data)
look up the dotenv npm module and using it to pull different environment variables based on if the app is in dev or production mode. via process.env.NODE_ENV
best practices is to .gitignore this file as it an expose credentials in public on github. Heroku will ignore it anyways, environment variables have to be set via the CLI, you can just copy and paste each on in one at a time and set with these commands or there is a page on heroku for adding this config. https://devcenter.heroku.com/articles/config-vars
same thing on the server side.
/**
* express.router() option? : https://stackoverflow.com/questions/61852261/nodemailer-not-working-on-heroku-deployment
*/
const express =
require('express'),
bodyParser = require('body-parser'),
nodemailer = require('nodemailer'),
cors = require('cors'), path = require('path'),
port = process.env.PORT || 3000;
require('dotenv').config();
let directory = process.env.NODE_ENV === 'development' ? 'public' : 'build',
publicPath = path.join(__dirname, '..', directory);
const app = express();
console.log(process.env.NODE_ENV)
app.use(cors());
app.use(express.static(publicPath));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, 'index.html'));
});
app.post('/send-email', (req, res) => {
console.log('request: ', req.body)
let data = req.body;
let transporter = nodemailer.createTransport({
service: 'gmail',
port: 465,
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});
let mailOptions = {
from: data.email,
to: process.env.EMAIL,
subject: `${data.subject}`,
html: `<p>${data.name}</p>
<p>${data.email}</p>
<p>${data.message}</p>`
};
// console.log('mailOptions are', mailOptions)
transporter.sendMail(mailOptions,[
(err, info) => {
if(err) {
res.send(err)
} else {
res.send(info.messageId)
}
transporter.close();
}]);
})
app.listen(port, () => {
console.log(`Server is up on port ${port}!`);
});
I'll keep you updated as to what I'm doing to get mine to work as well.
I was searching a similar issue. When I send contact mail from my local backend server port 3000, it worked fine. But after pushing to Heroku it didn't work. The issue was related to the .env file.
So by adding the ".env" codes directly to "Config Vars" in the settings panel of the Heroku dashboard, I was able to successfully send an email.
EMAIL_ID=your#email.com
PASSWORD=yourpassword
ie key: EMAIL-ID
value: your#email.com
etc.
All the best

Categories