how can i print a response from server using express and fetch? - javascript

i am getting object response when trying to use the response from express,this is the HTML and client js i am using
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<form method="post">
<input id="names" name="names" type="text" />
</form>
<button id="send">send</button>
<p id="text"></p>
<script>
document.getElementById("send").addEventListener("click", () => {
let datos = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
names: document.getElementById("names").value,
}),
};
fetch("/myaction", datos)
.then(function (response) {
document.getElementById("text").innerHTML = response;
})
.catch(() => {
document.getElementById("text").innerHTML = "Error";
});
});
</script>
</body>
</html>
i am trying to use the response of the server.js in the "text" element, the server is
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(express.json())
//Note that in version 4 of express, express.bodyParser() was
//deprecated in favor of a separate 'body-parser' module.
app.use(bodyParser.urlencoded({ extended: true }));
//app.use(express.bodyParser());
app.get('/', function(req, res) {
res.sendFile(__dirname + "/index.html");
});
app.post('/myaction', function(req, res) {
res.send(req.body.names);
});
app.listen(8088, function() {
console.log('Server running');
});
when fetch request myaction express return the name query but i cant use it on the fetch then because it print "[object Response]" instead the name form value, what can i do ?

The global fetch function returns a Promise that resolves to a Response object. This object contains all the information about the response, like headers, status, body, etc. To get the body of the response you'll need to decode the response first.
In your case you need to read the body as a string so we'll use response.text(). This is a method on the Response object. It also returns a promise which resolves to a string.
fetch("/myaction", datos)
.then(function (response) {
return response.text();
})
.then(function (text) {
document.getElementById("text").textContent = text;
})
.catch(() => {
document.getElementById("text").textContent = "Error";
});

The "response" that comes back from the fetch is an object that has more than just the data in the response. It's a Response object which means it contains the status code (like 200) as well as the data. Typically you can get the data from the response using response.json() if it's JSON format, or response.text() if it's text. These functions are asynchronous so also return a Promise. So your code can look like this:
fetch("/myaction", datos)
.then(function (response) {
return response.text(); // a Promise that will resolve to the data
})
.then(function (text) {
document.getElementById("text").innerHTML = text;
})
.catch(() => {
document.getElementById("text").innerHTML = "Error";
});
Whenever you see a string looking like [object Object] it means you are seeing a Javascript object that doesn't have a meaningful toString() function so that's the best it can do to show you the value. If you're not sure what kind of object it is, a good debugging technique is to output it using console.log(obj) so you can see what it looks like. That usually gives you a clue about what you really are working with.

Related

POST with Next.js and MongoDB

I'm getting a 500 when trying to make a POST with my Next.js Application. I can't seem to figure out why.
I'm using Next.js, and MongoDB and the GET requests are working fine.
Posts.js
import clientPromise from "../../lib/mongodb";
export default async function handler(req, res) {
const client = await clientPromise;
const db = client.db("quick_ticker_db");
switch (req.method) {
case "POST":
let bodyObject = JSON.parse(req.body);
let myPost = await db.collection("posts").insertOne(bodyObject);
res.json(myPost.ops[0]);
break;
case "GET":
const allPosts = await db.collection("posts").find({}).toArray();
res.json({ status: 200, data: allPosts });
break;
}
}
create.js
export default function CreateTicker() {
// Handles the submit event on form submit.
const handleSubmit = async (event) => {
// Stop the form from submitting and refreshing the page.
event.preventDefault()
// Get data from the form.
const data = {
ticker: event.target.ticker.value
}
// Send the data to the server in JSON format.
const JSONdata = JSON.stringify(data)
// API endpoint where we send form data.
const endpoint = '/api/posts'
// Form the request for sending data to the server.
const options = {
// The method is POST because we are sending data.
method: 'POST',
// Tell the server we're sending JSON.
headers: {
'Content-Type': 'application/json',
},
// Body of the request is the JSON data we created above.
body: JSONdata,
encodeBodyAsJSON: true
}
// Send the form data to our forms API on Vercel and get a response.
const response = await fetch(endpoint, options)
// Get the response data from server as JSON.
// If server returns the name submitted, that means the form works.
const result = await response.json()
result
}
return (
// We pass the event to the handleSubmit() function on submit.
<form onSubmit={handleSubmit}>
<label htmlFor="ticker">Ticker</label>
<input type="text" id="ticker" name="ticker" required />
<button type="submit">Submit</button>
</form>
)
}
ERROR:
POST http://localhost:3000/api/posts 500 (Internal Server Error)
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
"message":"Unexpected number in JSON at position 1"
RESPONSE:
<!DOCTYPE html>
<html>
<head>
<style data-next-hide-fouc="true">
body {
display: none
}
</style><noscript data-next-hide-fouc="true">
<style>
body {
display: block
}
</style>
</noscript>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta name="next-head-count" content="2" /><noscript data-n-css=""></noscript>
<script defer="" nomodule="" src="/_next/static/chunks/polyfills.js?ts=1664669437061"></script>
<script src="/_next/static/chunks/webpack.js?ts=1664669437061" defer=""></script>
<script src="/_next/static/chunks/main.js?ts=1664669437061" defer=""></script>
<script src="/_next/static/chunks/pages/_app.js?ts=1664669437061" defer=""></script>
<script src="/_next/static/chunks/pages/_error.js?ts=1664669437061" defer=""></script>
<script src="/_next/static/development/_buildManifest.js?ts=1664669437061" defer=""></script>
<script src="/_next/static/development/_ssgManifest.js?ts=1664669437061" defer=""></script><noscript
id="__next_css__DO_NOT_USE__"></noscript>
</head>
<body>
<div id="__next" data-reactroot=""></div>
<script src="/_next/static/chunks/react-refresh.js?ts=1664669437061"></script>
<script id="__NEXT_DATA__" type="application/json">
{"props":{"pageProps":{"statusCode":500}},"page":"/_error","query":{"__NEXT_PAGE":"/api/posts"},"buildId":"development","isFallback":false,"err":{"name":"SyntaxError","source":"server","message":"Unexpected number in JSON at position 1","stack":"SyntaxError: Unexpected number in JSON at position 1\n at JSON.parse (\u003canonymous\u003e)\n at handler (webpack-internal:///(api)/./pages/api/posts.js:12:35)\n at processTicksAndRejections (internal/process/task_queues.js:95:5)\n at async Object.apiResolver (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/api-utils/node.js:366:9)\n at async DevServer.runApi (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/next-server.js:481:9)\n at async Object.fn (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/next-server.js:735:37)\n at async Router.execute (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/router.js:247:36)\n at async DevServer.run (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/base-server.js:347:29)\n at async DevServer.run (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/dev/next-dev-server.js:709:20)\n at async DevServer.handleRequest (/Users/Projects/Personal/quick-ticker-web/node_modules/next/dist/server/base-server.js:285:20)"},"gip":true,"scriptLoader":[]}
</script>
</body>
</html>
For the record GET requests are working just fine.
I think that is because your post logic throwing error:
let bodyObject = JSON.parse(req.body);
let myPost = await db.collection("posts").insertOne(bodyObject);
run this code in try/catch block.
your code is not reaching res.json(myPost.ops[0])

POST request not working -- sending empty objects [NodeJS]

I am building this school project where we have to create out own API in NodeJs and free-choice frontend. I wrote the following code:
[In public map] app.js
function getAll() {
console.log("Get all")
makeRequest("/poems", "GET")
}
async function getRandomPoem() {
const ids = [1, 2, 3, 4, 5, 6, 7]
const randomId = ids[Math.floor(Math.random() * ids.length)]
const arrayofPoems = await fetch("/poems/" + randomId, {method: "GET"})
const data = await arrayofPoems.json()
const titleBox = document.getElementById("title")
const authorBox = document.getElementById("author")
const textBox = document.getElementById("text")
titleBox.innerText = data.title
authorBox.innerText = data.author
textBox.innerText = data.text
}
function addPoem() {
event.preventDefault();
let title = document.getElementById("titleInput").value
let author = document.getElementById("authorInput").value
let text = document.getElementById("textInput").value
let newPoem = [{
id: 8,
title: "Aaa",
author: "Ccc",
text: "Ddd"
}]
makeRequest("/poems/", "post", newPoem)
}
async function makeRequest(url, reqMethod, body) {
const response = await fetch(url, {
// headers = { "Content-Type": "application/json" },
method: reqMethod,
body:JSON.stringify(body)
})
console.log(response)
const data = await response.json()
console.log(data)
}
[Here the requests to local server] server.js
const express = require('express');
const { poems } = require('./Poems/poemsArray');
const app = express();
const port = 8080;
const allPoems = require('./Poems/poemsArray')
app.use(express.json())
app.use("/", express.static('public'))
app.listen(port, console.log(`App listening on port ${port}`))
// ---------------- POEMS RESOURCE, All endpoints ------------------ //
// Get all
app.get('/poems', (req, res, next) => {
res.json(allPoems)
})
// Get specific
app.get('/poems/:id', (req, res, next) => {
const id = req.params.id
const onePoem = allPoems.find((poem) => poem.id == id)
if(onePoem) {
res.json(onePoem)
} else {
res.status(404).json({ status: "Poem not found! "})
}
})
// Post a poem
app.post('/poems', (req, res, next) => {
allPoems.push(req.body)
res.json({ status: "A new poem has been posted!"})
})
[And last, the HTML with the input fields, where the values should be sent with the POST req] index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Poems from outer space</title>
<script src="app.js"></script>
</head>
<body>
<div id="container">
<div id="poem-container">
<h1 style="color:red;text-align:center;">Poems</h1>
<p style="text-align: center;">Generate a random poem about space!
<button onclick="getRandomPoem()">Generate my poem!</button>
</p>
<div id="showPoem">
<h1 id="title"><!-- Title of poem injected --></h1>
<h2 id="author"><!-- Author of poem injected --></h2>
<p id="text"><!-- Text of poem injected --></p>
</div>
<div id="image-container">
<!-- INJECTED BY EXTERNAL NASA API -->
<!-- EXAMPLE IMAGE TO TEST DELETE WHEN API WORKS -->
<img src="img/apod.jpg" alt="Test Image" width="600px" id="img">
</div>
</div>
<div id="form-container">
<form method="post" action="/poems">
<h1>Send us your poem!</h1>
<label>Your title:</label> <br>
<input type="text" requirede name="title" id="titleInput"> <br>
<label>Your name:</label> <br>
<input type="text" required name="author" id="authorInput"> <br> <br>
<label>Your poem:</label> <br>
<input type="text" required name="text" id="textInput" style="width:500px;height:500px">
<br>
<button type="submit" onclick="addPoem()">Send</button>
</form>
</div>
</div>
</body>
</html>
In the function addPoem() the let newPoem is for testing purposes. The title, author and text should be coming from the form.
Anyone can see what I did wrong?
EDIT: in the makeRequest function the header is commented out, that is because if I leave it in my code, suddenly none of the request work anymore?
Thanks to everybody!
you use headers = which is not valid . try headers : {} .
When you get empty object , try logging the request. It is also possible that the body get sended as a string,which express.json() middleware cannot parse the data. As a result, you get empty object.
async function makeRequest(url, reqMethod, body) {
const response = await fetch(url, {
headers : { "Content-Type": "application/json" },
method: reqMethod,
body:JSON.stringify(body)
})
console.log(response)
const data = await response.json()
console.log(data)
}
If you are trying to access postman after a while it can also cause issue while sending body.
In my case I had done all changes in API, added router,removed validation etc
but at last the culprit was postman as whatever data I was sending, it was showing request.body as {}(empty).
After I re-installed postman it worked!
I just could felt more joyful, it took my 3-4 hours
So you can consider this option as well.

Can't read content of online file in Node.js with XMLHttpRequest on the client [duplicate]

How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.
Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.
Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:
const http = require('http');
const https = require('https');
/**
* getJSON: RESTful GET request returning JSON object(s)
* #param options: http options object
* #param callback: callback to pass the results JSON object(s) back
*/
module.exports.getJSON = (options, onResult) => {
console.log('rest::getJSON');
const port = options.port == 443 ? https : http;
let output = '';
const req = port.request(options, (res) => {
console.log(`${options.host} : ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
output += chunk;
});
res.on('end', () => {
let obj = JSON.parse(output);
onResult(res.statusCode, obj);
});
});
req.on('error', (err) => {
// res.send('error: ' + err.message);
});
req.end();
};
It's called by creating an options object like:
const options = {
host: 'somesite.com',
port: 443,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
And providing a callback function.
For example, in a service, I require the REST module above and then do this:
rest.getJSON(options, (statusCode, result) => {
// I could work with the resulting HTML/JSON here. I could also just return it
console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);
res.statusCode = statusCode;
res.send(result);
});
UPDATE
If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:
Microsoft typed-rest-client
Try using the simple http.get(options, callback) function in node.js:
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.
Request and Superagent are pretty good libraries to use.
note: request is deprecated, use at your risk!
Using request:
var request=require('request');
request.get('https://someplace',options,function(err,res,body){
if(err) //TODO: handle err
if(res.statusCode === 200 ) //etc
//TODO Do something with response
});
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for GET method request:
var requestify = require('requestify');
requestify.get('http://example.com/api/resource')
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
}
);
This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.
let http = require("http"),
https = require("https");
/**
* getJSON: REST get request returning JSON object(s)
* #param options: http options object
*/
exports.getJSON = function (options) {
console.log('rest::getJSON');
let reqHandler = +options.port === 443 ? https : http;
return new Promise((resolve, reject) => {
let req = reqHandler.request(options, (res) => {
let output = '';
console.log('rest::', options.host + ':' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', () => {
try {
let obj = JSON.parse(output);
// console.log('rest::', obj);
resolve({
statusCode: res.statusCode,
data: obj
});
}
catch (err) {
console.error('rest::end', err);
reject(err);
}
});
});
req.on('error', (err) => {
console.error('rest::request', err);
reject(err);
});
req.end();
});
};
As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler
router.get('/:id', (req, res, next) => {
rest.getJSON({
host: host,
path: `/posts/${req.params.id}`,
method: 'GET'
}).then(({ statusCode, data }) => {
res.json(data);
}, (error) => {
next(error);
});
});
On error it delegates the error to the server error handling middleware.
Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.
Here are a couple of code examples for Node.js:
var unirest = require('unirest')
// GET a resource
unirest.get('http://httpbin.org/get')
.query({'foo': 'bar'})
.query({'stack': 'overflow'})
.end(function(res) {
if (res.error) {
console.log('GET error', res.error)
} else {
console.log('GET response', res.body)
}
})
// POST a form with an attached file
unirest.post('http://httpbin.org/post')
.field('foo', 'bar')
.field('stack', 'overflow')
.attach('myfile', 'examples.js')
.end(function(res) {
if (res.error) {
console.log('POST error', res.error)
} else {
console.log('POST response', res.body)
}
})
You can jump straight to the Node docs here
Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.
Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)
For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)
Install (npm): npm install axios
Example GET request:
const axios = require('axios');
axios.get('https://google.com')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
Github page
Update 10/02/2022
Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful.
If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:
var get = require('simple-get');
get('http://example.com', function (err, res) {
if (err) throw err;
console.log(res.statusCode); // 200
res.pipe(process.stdout); // `res` is a stream
});
Use reqclient: not designed for scripting purpose
like request or many other libraries. Reqclient allows in the constructor
specify many configurations useful when you need to reuse the same
configuration again and again: base URL, headers, auth options,
logging options, caching, etc. Also has useful features like
query and URL parsing, automatic query encoding and JSON parsing, etc.
The best way to use the library is create a module to export the object
pointing to the API and the necessary configurations to connect with:
Module client.js:
let RequestClient = require("reqclient").RequestClient
let client = new RequestClient({
baseUrl: "https://myapp.com/api/v1",
cache: true,
auth: {user: "admin", pass: "secret"}
})
module.exports = client
And in the controllers where you need to consume the API use like this:
let client = require('client')
//let router = ...
router.get('/dashboard', (req, res) => {
// Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
client.get("reports/clients")
.then(response => {
console.log("Report for client", response.userId) // REST responses are parsed as JSON objects
res.render('clients/dashboard', {title: 'Customer Report', report: response})
})
.catch(err => {
console.error("Ups!", err)
res.status(400).render('error', {error: err})
})
})
router.get('/orders', (req, res, next) => {
// GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
.then(orders => {
res.render('clients/orders', {title: 'Customer Orders', orders: orders})
})
.catch(err => someErrorHandler(req, res, next))
})
router.delete('/orders', (req, res, next) => {
// DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
client.delete({
"uri": "orders/{client}/{id}",
"params": {"client": "A987", "id": 1234}
})
.then(resp => res.status(204))
.catch(err => someErrorHandler(req, res, next))
})
reqclient supports many features, but it has some that are not supported by other
libraries: OAuth2 integration and logger integration
with cURL syntax, and always returns native Promise objects.
If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:
function getCode(host, port, path, queryString) {
console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")
// Construct url and query string
const requestUrl = url.parse(url.format({
protocol: 'http',
hostname: host,
pathname: path,
port: port,
query: queryString
}));
console.log("(" + host + path + ")" + "Sending GET request")
// Send request
console.log(url.format(requestUrl))
http.get(url.format(requestUrl), (resp) => {
let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {
console.log("GET chunk: " + chunk);
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("GET end of response: " + data);
});
}).on("error", (err) => {
console.log("GET Error: " + err);
});
}
Don't miss requiring modules at the top of your file:
http = require("http");
url = require('url')
Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:
https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
## you can use request module and promise in express to make any request ##
const promise = require('promise');
const requestModule = require('request');
const curlRequest =(requestOption) =>{
return new Promise((resolve, reject)=> {
requestModule(requestOption, (error, response, body) => {
try {
if (error) {
throw error;
}
if (body) {
try {
body = (body) ? JSON.parse(body) : body;
resolve(body);
}catch(error){
resolve(body);
}
} else {
throw new Error('something wrong');
}
} catch (error) {
reject(error);
}
})
})
};
const option = {
url : uri,
method : "GET",
headers : {
}
};
curlRequest(option).then((data)=>{
}).catch((err)=>{
})

Can I response.end() inside request.on(end)?

I'm learning node.js. I have a client form, from which I send to my server some data and refactor it somehow in a module makeRequest. The module returns a promise, which I want to resolve with response to the client.
So I might think that I could do something like this:
let post = '';
const server = http.createServer(function (req, res) {
const readHtml = fs.createReadStream(__dirname + '/view/form.html', 'utf8');
readHtml.pipe(res);
});
server.on('request', processPost);
function processPost(request, response) {
let body = '';
if (request.method === 'POST') {
request.on('data', function (data) {
body += data;
if (body.length > 1e6) {
request.connection.destroy();
}
});
request.on('end', function () {
post = JSON.parse(body);
makeRequest(post.text)
.then(data => {
response.end(data);
})
.catch(err => {
console.log(err);
});
});
}
}
server.listen(3000, 'localhost');
This for me means that as soon as I retreive the refactored data I immediately send it back to client with response.end(data).
But suddenly the data does not return to the client if I do like this. It does, if I write response.end(data) after request.on('end'). But this is synchronous way and therefore when I run such code, there will be no data anyhow.
What can I do to make it work as I want to?
If, as said in a discussion below the question, you just want a default page accessed in a browser, make it conditional
const server = http.createServer(function(req, res) {
if ( req.method == "GET" ) {
const readHtml = fs.createReadStream(__dirname + '/view/form.html', 'utf8');
readHtml.pipe(res);
}
});
This way both GETs and POSTs are handled correctly.
My advice would be to use a more organized approach using any framework, Express should do fine. This way you could be a more clean approach to define different routes and request types.

Execute Python script with Node.js

I am trying to execute Python Script when I click on HTML button. Both files are on a Node.js Server. When I press the button I get this message in the browser console:
app.js:5 Uncaught ReferenceError: runPython is not defined
I am not sure how to write my AJAX script to call the runPython() function on my Node web server file. Below is my code:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"> </script>
</head>
<body>
<button id="myButton">Run Python Script</button>
<script src="app.js"></script>
</body>
</html>
app.js
$('#myButton').click(function() {
$.ajax({
url: "",
success: function(data) {
runPython();
},
});
});
webserver.js (node.js)
'use strict';
const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
let mimes = {
'.htm': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript'
}
//Have ajax call it to execute Python Script
function runPython(){
let exec = require('child_process').exec;
exec('python myscript.py', (error, stdout, stderr) => {
console.log(stdout);
});
}
function fileAccess(filepath) {
return new Promise((resolve, reject) => {
fs.access(filepath, fs.F_OK, error => {
if(!error) {
resolve(filepath);
} else {
reject(error);
}
});
});
}
function streamFile(filepath) {
return new Promise((resolve, reject) => {
let fileStream = fs.createReadStream(filepath);
fileStream.on('open', () => {
resolve(fileStream);
});
fileStream.on('error', error => {
reject(error);
});
});
}
function webserver(req, res) {
// if the route requested is '/', then load 'index.htm' or else
// load the requested file(s)
let baseURI = url.parse(req.url);
let filepath = __dirname + (baseURI.pathname === '/' ? '/index.htm' : baseURI.pathname);
let contentType = mimes[path.extname(filepath)];
fileAccess(filepath)
.then(streamFile)
.then(fileStream => {
res.writeHead(200, {'Content-type': contentType});
//res.end(content, 'utf-8');
fileStream.pipe(res);
})
.catch(error => {
res.writeHead(404);
res.end(JSON.stringify(error));
});
}
http.createServer(webserver).listen(3000, () => {
console.log('Webserver running on port 3000');
});
How should I write the AJAX code so that the function in webserver.js will run?
The browser is loading the script at that url. This is treated as either data or text. Browsers don't generally run Python so Working As Intended.
You need to make an ajax request to the server that will run some code that will invoke your python script. You're missing the middle part of that process, and simply requesting the contents of myscript.py as text.
Something like:
$('#myButton').click(function() {
$.ajax({
url: "/invoke-script"
});
});
I am not familiar with Node, but I imagine you have some sort of controller and the ability to execute commands (maybe using https://www.npmjs.com/package/exec-sync). In that controller you then invoke your python script and do what you need with the output.
Think about this script like an executable. If your URL points to some *.exe file, clicking on the URL tells the web browser to download the resource. The same happens to Python script.
If you want to run some python code, try to handle HTTP request instead with simple HTTP server. This is the most common way to execute some actions on HTTP request. Check documentation for SimpleHTTPServer and BaseHTTPServer.
Here and here you can find some code snippet for simple server implementation.

Categories