My code in server express for seo stuff react-app hasn't work as expected, what im doing wrong? - reactjs

I made an express server for my react application, for seo optimization. I need to dynamically substitute meta tags in order to make the preview of the post look attractive when I post it on social networks. Inside the router, I make a get request via axios to the backend to get data from a specific post, and then from the received response I pull out the data from the required fields and put it in meta tags. In order to replace old data that is not fresh, I made temporary variables with data for meta tags and after a new request, temporary data is replaced with new ones and so on in a circle. My code is not working as I expect, what could be the problem? Is there a way to store temporary variables right inside the index file or do I need to make a temporary storage?
right down my index.js file:
const axios = require('axios');
const path = require('path');
const express = require('express');
const fs = require('fs');
const baseUrl = 'https://itnews.pro/pre/api';
const app = express();
const PORT = process.env.MIDDLEWARE_EXPRESS_PORT || 8084;
const indexPath = path.resolve(__dirname, '..', 'build', 'index.html');
let tempMainTitle = 'IT-NEWS';
let tempMetaTitle = '__META_OG_TITLE__';
let tempMetaUrl = '__META_OG_URL__';
let tempMetaCover = '__META_OG_IMAGE__';
let tempMetaDescription = '__META_OG_DESCRIPTION__';
let mainTitle = '';
let metaTitle = '';
let metaUrl = '';
let metaCover = '';
let metaDescription = '';
app.get('/*', (req, res, next) => {
let urlForRequest = `${baseUrl + "/publication/objects" + req.url.replace('/news/', "/").replace("/events/", "/") + "?format=json"}`;
if (req.url.includes('news') || req.url.includes('events') || req.url.includes('arcticles')) {
axios.get(urlForRequest)
.then((a_res) => {
//settings data for meta tags
mainTitle = a_res?.data?.title;
metaTitle = a_res?.data?.title;
metaUrl = baseUrl + a_res?.data?.id_full;
metaCover = baseUrl + a_res?.data?.cover;
metaDescription = a_res?.data?.short_content.replace('<p>', '').replace('</p>', '');
//cahce variable for replacing in the future with new data
tempMetaTitle = a_res?.data?.title;
tempMetaUrl = baseUrl + a_res?.data?.id_full;
tempMetaCover = baseUrl + a_res?.data?.cover;
tempMetaDescription = a_res?.data?.short_content.replace('<p>', '').replace('</p>', '');
tempMainTitle = a_res?.data?.title
return res.data;
})
.catch((err) => {
console.log("cant fetch data from expres: ", err);
})
.finally((console.log("Ooops")))
}
fs.readFile(indexPath, 'utf8', (err, htmlData) => {
if (err) {
console.error('Error during file reading', err);
return res.status(404).end()
}
htmlData = htmlData.replace(`<title>${tempMainTitle}</title>`, `<title>${mainTitle}</title>`)
.replace(tempMetaTitle, metaTitle)
.replace('__META_OG_TYPE__', 'article')
.replace(tempMetaDescription, metaDescription)
.replace(tempMetaCover, metaCover)
.replace(tempMetaUrl, metaUrl);
return res.send(htmlData);
});
});
//path to static that will be rendered
app.use(express.static(path.resolve(__dirname, '..', 'build')));
app.listen(PORT, (error) => {
if (error) {
return console.log('Error during app startup', error);
}
console.log("listening on " + PORT + "...");
});
I tried to make the request and reading from the file asynchronous and it didn't help.

Related

How to convert Blob back into a file with nodejs?

I'm currently working on an application that allows the user to upload a file which gets sent to a express server that then converts that file into a bytearray that I can then store somewhere else.
However, I need to be able to convert this bytearray back into a file and send it back to the user. This is my current code in the express API:
app.post("/upload", async (req, res) => {
const file = req.files.file;
const filePath = "divali";
file.mv(filePath, async (err) => {
const nfile = fs.readFileSync(filePath);
let fileData = nfile.toString("hex");
let result = [];
for (var i = 0; i < fileData.length; i += 2)
result.push("0x" + fileData[i] + "" + fileData[i + 1]);
console.log(result);
var pfile = new Blob([result], { type: "application/pdf" });
// var fileURL = URL.createObjectURL(pfile);
console.log(pfile);
pfile.lastModifiedDate = new Date();
pfile.name = "some-name";
console.log(pfile);
});
});

I have a functioning express server, how do I make this work with a React App

Here is my server.js
const port = process.env.PORT || 5000;
const express = require('express');
const bodyParser = require('body-parser');
const multer = require('multer');
const uuidv4 = require('uuid/v4');
const path = require('path');
const htmlparser = require("htmlparser2");
const fs = require("fs");
let filename = '';
// configure storage
const storage = multer.diskStorage({
destination: (req, file, cb) => {
/*
Files will be saved in the 'uploads' directory. Make
sure this directory already exists!
*/
cb(null, './uploads');
},
filename: (req, file, cb) => {
/*
uuidv4() will generate a random ID that we'll use for the
new filename. We use path.extname() to get
the extension from the original file name and add that to the new
generated ID. These combined will create the file name used
to save the file on the server and will be available as
req.file.pathname in the router handler.
*/
const newFilename = `${uuidv4()}${path.extname(file.originalname)}`;
cb(null, newFilename);
},
});
// create the multer instance that will be used to upload/save the file
const upload = multer({ storage });
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/upload", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post('/upload', upload.single('selectedFile'), (req, res) => {
let summary ='';
let counter =0;
let times = [];
let days = [];
let building = [];
let date = [];
let isGood = false;
filename = req.file.filename;
fs.readFile('./uploads/'+filename, 'utf8', function(err, data) {
if (err) throw err;
//console.log(data);
const parser = new htmlparser.Parser({
onopentag: function(name, attribs){
// summary="This table lists the scheduled meeting times and assigned instructors for this class.."
if(name === "tr" && attribs === 'summary'){
//console.log(attribs);
}
},
ontext: function(text){
if(text==='Class'){
isGood=true;
counter++;
}
if(text!="Lecture"&&text!="Class"&&isGood){
if(counter===2){
times.push(text);
}
if(counter===4){
days.push(text);
}
if(counter===6){
building.push(text);
}
if(counter===8){
date.push(text);
}
counter++;
console.log(text);
console.log(counter);
summary = summary+text;
}
if(text==="Lecture"){
isGood=false;
counter=0;
}
},
}, {decodeEntities: true});
parser.write(data);
parser.end();
console.log("STTTTTTTTTTTTTTTTTTTTTTTAAAAAAAAAAAAAAAAAAAAAAAAAARRRRRRRRRRRRRRRRRRRRRTTTTTTTTTTTTTTT");
console.log(building);
console.log(times);
console.log(date);
console.log(days);
fs.unlink('./uploads/'+filename, function(error) {
if (error) {
throw error;
}
console.log('Deleted filename', filename);
})
});
/*
We now have a new req.file object here. At this point the file has been saved
and the req.file.filename value will be the name returned by the
filename() function defined in the diskStorage configuration. Other form fields
are available here in req.body.
*/
res.send();
});
app.listen(port, () => console.log(`Server listening on port ${port}`));
I can get this to run while running "npm start" first then this. This doesn't check if anything else is running on port 3000 so they both are able to run on port 3000. I don't like this and I don't know if this will work once we build our React App and begin hosting it. How can I combine this code with react app to get it to run on a single server instead of two? I've tried literally combining start.js and this code, however start.js is obviously just for development purposes and not the final product. How can I serve up my html to the user and still have the front end sending to the back end.
Suprisingly enough I had come here after researching this for hours and immediately after posting the question if found the answer. The simple answer is:
add "proxy": "http://localhost:PORT"
where PORT = express server port it is running on
I still however don't know if this works with the build product however it works with the quick start server.
All credit goes to this lovely website https://dev.to/loujaybee/using-create-react-app-with-express

How to download files using axios.post from webapi

I have a complex object parameter that I need to send as post, as it could be too long for querystring. The post call is asking to have an excel file dynamically generated and then downloaded asynchronously. But all of this is happening inside of a react application. How does one do this using axios.post, react, and webapi? I have confirmed that the file does generate and the download up to the response does come back, but I'm not sure how to actually open the file. I have a hidden iframe that I'm trying to set the path, src, of the file to, but I dont know what response property to use.
// webapi
[HttpPost]
public HttpResponseMessage Post([FromBody]ExcelExportModel pModel)
{
var lFile = ProductDataModel.GetHoldingsExport(pModel);
var lResult = new HttpResponseMessage(HttpStatusCode.OK);
lResult.Content = new ByteArrayContent(lFile);
lResult.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "HoldingsGridExport.xls"
};
lResult.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return lResult;
}
// client side api
static getHoldingsExport({ UserConfigurationID, UserID, Configurations, ViewName, SortModel, FilterModel, UserConfigType, IsDefault, LastPortfolioSearchID = null, ProductId }) {
const filterModel = JSON.stringify(FilterModel); // saving as string as this model is dynamically generated by grid out of my control
const sortModel = JSON.stringify(SortModel);
let params = JSON.stringify({
UserConfigurationID,
UserID,
Configurations,
ViewName,
filterModel,
sortModel,
UserConfigType,
IsDefault,
LastPortfolioSearchID,
ProductId
});
return axiosInstance.post("/api/HoldingsExport", params);
}
// client side app call to get file
HoldingsApi.getHoldingsExport(config)
.then(function(response) {
debugger;
let test = response;
})
.catch(error => {
toastr.success('Failed to get export.');
});
This is how I've achieved file downloads by POSTing via Axios:
Axios.post("YOUR API URI", {
// include your additional POSTed data here
responseType: "blob"
}).then((response) => {
let blob = new Blob([response.data], { type: extractContentType(response) }),
downloadUrl = window.URL.createObjectURL(blob),
filename = "",
disposition = response.headers["content-disposition"];
if (disposition && disposition.indexOf("attachment") !== -1) {
let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/,
matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, "");
}
}
let a = document.createElement("a");
if (typeof a.download === "undefined") {
window.location.href = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
}).catch((error) => {
// ...
});
Just in case the above solution does not serve you quite well, here is how I could be able to download videos that are hosted on S3 AWS buckets,
const handleDownload = () => {
const link = document.createElement("a");
link.target = "_blank";
link.download = "YOUR_FILE_NAME"
axios
.get(url, {
responseType: "blob",
})
.then((res) => {
link.href = URL.createObjectURL(
new Blob([res.data], { type: "video/mp4" })
);
link.click();
});
};
And I trigger handleDownload function in a button with onClick.
The url in the function has the video URL from S3 buckets

Downloading from S3 in node and opening in a new window

My Angular 1 application saves files to S3 and allows for a wide variety of files types.
When I retrieve the objects I use the following code:
export function show(req, res) {
const s3 = new aws.S3();
const s3Params = {
Bucket: S3_BUCKET,
Key: req.query.key + ''
};
res.attachment(req.query.key + '');
var fileStream = s3.getObject(s3Params).createReadStream();
fileStream.pipe(res);
}
I would like to open the received file on the client in a new window (just like on the AWS console) but I can't figure out how to go about it.
For example on the client side does not work at all:
.then(
(data) => {
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
)
I really don't understand how the concept of data streams works.
If you don't have to download pdf, you may open it directly from s3.
s3client.getResourceUrl("your-bucket", "some-path/some-key.jpg");
This will return you url to the file.
So you need code like:
export function show(req, res) {
this.s3client = new aws.S3({
accessKeyId: options.accessKeyId,
secretAccessKey: options.secretAccessKey,
region: options.region
})
let resourceUrl = s3client.getResourceUrl(S3_BUCKET, req.query.key + '');
window.open(resourceUrl, '_blank');
}
I'm sorry, can't test it right now, but try. Should work.
All I had to do was get a signedUrl for the resource for this to work much simpler than what I was trying to do.
export function show(req, res) {
const s3 = new aws.S3();
const s3Params = {
Bucket: S3_BUCKET,
Key: req.query.key + ''
};
s3.getSignedUrl('getObject', s3Params, (err, data) => {
if (err) {
console.log(err);
return res.end();
}
const returnData = {
signedRequest: data,
};
res.write(JSON.stringify(returnData));
res.end();
});
}
and on the client all I have to do is open the link in a new tab:
openDoc(doc) {
this.$http()
.then(
(data) => {
this.$window.open(data.data.signedRequest, '_blank')
}
)
.catch(
(err) => {
this.Notification.error('failed to download attachment');
}
)
}

How to upload a file using filesystem I/O in Mean app?

I am using fs for uploading a file in my web app but the console shows that the file has been saved to the desired location which I have entered but the file doesn't show up there.
The code is here:-
var fs = require('fs-extra');
var path = require('path');
module.exports.updatePhoto = function(req,res) {
var file = req.files.file;
var userId = req.body.userId;
console.log("User "+ userId +" is submitting ", file);
var uploadDate = new Date();
var tempPath = file.path;
var targetPath = path.join(__dirname, "../../uploads/" + userId + uploadDate +file.name);
var savePath = "/uploads/" + userId + uploadDate + file.name;
fs.rename(tempPath, targetPath,function(err){
if(err) {
console.log(err);
}
else {
User.findById(userId, function(err, userData){
var user = userData;
user.image = savePath;
user.save(function(err){
if(err) {
console.log("failed")
res.json({status: 500})
}
else {
console.log("saved");
res.json({status: 200})
}
})
})
}
})
};
Are you using connect-multiparty to get the file from Express? https://github.com/expressjs/connect-multiparty
I ended up loading the files to AWS. So the best I can offer is the code to do that. It is basically free for my usage and I use docker to rebuild my site so this make it more flexible.
My File.Js:
'use strict';
module.exports = function (app) {
/**
* Module dependencies.
*/
var auth = require('../config/auth'),
api = {},
multiparty = require('connect-multiparty'),
multipartyMiddleware = multiparty(),
path = require('path'),
uuid = require('node-uuid'),
fs = require('fs'),
S3FS = require('s3fs');
var s3fsImpl = new S3FS('FOLDER_NAME_ENTER_HERE', {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
/**
* Saves the logo file to the server
*/
api.uploadImage = function(req, res) {
// We are able to access req.files.file thanks to the multiparty middleware
var folder = req.params.folder;
var file = req.files.file;
var filename = uuid.v4() + path.extname(file.name);
var stream = fs.createReadStream(file.path);
s3fsImpl.writeFile(folder + '/' + filename, stream).then(function () {
fs.unlink(file.path, function (err) {
if (err) {
console.error(err);
}
});
return res.status(200).json({'fileName': filename, 'url': 'https://s3-us-west-2.amazonaws.com/AWS_FOLDER_ENTER_HERE' + folder + '/' + filename});
});
};
/**
* Routes
*/
app.route('/api/files/:folder/uploadImage')
.post(auth.jwtCheck, multipartyMiddleware, api.uploadImage);
};

Resources