node proxy closed connection unexpectedly - python

my system runs python code with apache and mod_wsgi.
node proxyes the connection to apache.
in the python script i serve a file in response to a http get.
when requesting the connction cuts unexpectedly in the middle.
the node code:
var server = https.createServer(httpsOptions,function (req, res) {
var result=req.url.match(/^\/(.*?)(\/.*?)$/);
if (!(result&&result[1]=='socket.io')) {
return proxy.proxyRequest(req, res);
}
});
when i make the request to apache if works fine.
it also works fine for the first request affter a node restart.

Related

How to setup SocketIO connection to NodeJS websocket from Python client?

I've got a simple nodejs server that runs socketio and I can do 2 way communication with the client from the HTML. Now I'm also trying to connect to the same nodejs websocket from a Python script, but not getting connected.
Simplified Node JS webserver:
var http = require('http').createServer(handler);
var fs = require('fs');
var io = require('socket.io')(http)
http.listen(8080);
function handler (req, res) {
fs.readFile(__dirname + '/public/index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
return res.end();
});
}
io.sockets.on('connection', function (socket) {
setInterval(() => {
socket.emit('temp', 'tempfromserver')
}, 1000)
});
The Python script that wants to connect to the nodejs with websocket:
import socketio
sio = socketio.Client();
sio.connect('http://localhost:8080')
#sio.event
def message(data):
print('received message')
def connect():
print('socketio connected')
Is it possible to connect with a websocket via socketio to the nodejs server? If so, what am I doing wrong?
End goal is to collect sensor data from python script on raspberry pi and send to nodejs server which in its turn saves it to DB and sends through to HTMl client. Perhaps there is a better setup to do this.
I believe I asked a similar question and got an answer. My setup was a little different, and used a web-socket, but it will at least allow you to connect between Node JS and Python, and then maybe you can build from there, Using Socket IO and aiohttp for data transfer between node JS and Python. The setup was also originally based off a html script on the node JS side, so that may help as well in comparing it to your setup.

Which ports do I use to send get requests for a full-stack Vue/Flask/MongoDB project?

I've built a mongo database and a Python/PyMongo/Flask script. Now I'm learning Vue so I can put that data on a webpage, but I'm having trouble understanding which ports to use in my path. I understand mongodb uses 27017, Flask uses 5000, and Vue uses 8080.
Here's my Python/PyMongo/Flask script (app.py). Since I can't give you the entire database data, I altered the 'findNames' function to just return a string.
from flask import Flask, jsonify
from flask_cors import CORS
from pymongo import MongoClient
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
client = MongoClient('localhost', 27017)
db = client.argodb
CORS(app)
#app.route('/searchDB', methods=['GET'])
def findNames():
return jsonify('The database is connected!')
if __name__ == '__main__':
app.run()
And on the client side, here's my Vue index.js:
import Vue from 'vue';
import Router from 'vue-router';
import searchDB from '#/components/searchDB';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/searchDB',
component: searchDB,
},
],
});
Here's the main component, App.vue:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
And here's my component, searchDB.vue:
<template>
<div id="search-db">
<h1>Database Search</h1>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'searchDB',
data() {
return {
msg: '',
};
},
methods: {
getMessage() {
const path = 'http://localhost:5000/searchDB';
axios.get(path)
.then((res) => {
this.msg = res.data;
})
.catch((error) => {
// eslint-disable-next-line
console.error(error);
});
},
},
created() {
this.getMessage();
},
};
</script>
<style>
</style>
You have each application running on its own port -- MongoDB running on 27017, Flask running on 5000 and Vue (npm) running on 8080. The chain of events that you'd ideally like to happen is this.
Vue uses axios to send an http request to Flask on port 5000
Flask receives the request and handles the request and recognizes that it needs to retrieve data from the database before sending a response, so it submits a query to Mongo which is running on port 27017.
Mongo returns the requested data to Flask
Flask formats the data into an appropriate http response and returns it to the requester (Vue)
The axios call receives its response and reacts to the response data, storing the data if the response was successful (e.g. status code 200 for a Get)
Since there are a lot of steps along the way that need to go correctly, it's a good idea to test in small pieces first to ensure the whole chain is working properly. I would suggest:
Test to ensure Flask is connecting to Mongo properly and can retrieve data
Next use a curl statement or Postman to check to see if your Flask webserver is handling calls to http://localhost:5000/searchDB properly. Note that if you can also take Mongo out of the equation (as you have done) for this test by just having the call return a string.
Once you are sure you can make calls to that endpoint (/searchDB) successfully, then you can start testing Vue and Axios. This is where you are likely to run into CORS issues.
If you are able to get everything working but cannot resolve the CORS issues, then another possible setup would be to stick NGINX in front of Flask and Vue. This solution involves running NGINX on its own port, let's say port 3000 and then configuring the server to proxy for ports 5000 and 8080. Then you would change your Vue/Axios code to make calls to port 3000 instead of port 5000, which avoids CORS since this would then be the same port that Vue is being served on through NGINX.

I need to host node js through python

var util = require('util');
var exec = require('child_process').spawn;
var run = exec('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002']);
run.stdout.on('data', function(data){
console.log('stdout: ' + data.toString());
});
run.stderr.on('data', function (data) {
console.log('stderr: ' + data.toString());
});
test.py
from bottle import route, run, template
#route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=9002)
I am new to node js and python just i want do communicate between node js to python with localhost. A simple python script with localhost url to hit node js url after running node js scrpit whih call python script in node and host the same on web browser.
Not entirely sure I see the problem. Your code works.
1) Make sure you access localhost:9002
2) If you meant to run your bottle code, then use
var run = exec('/usr/bin/python', ['/path/to/bottle_server.py']);
As for communicating back and forth between the Python code and the Node.js code, then you need sockets. Some libraries to look at could include socket.io or use a messaging queue like zmq.
If you want one-way communication to your python API, then you need to perform HTTP requests to http://localhost:9002 from the Node code. Alternatively, Node is very much capable of the same functionality you've included in the Python code on its own.
EDIT
Regarding below comments, here is an updated script. You need to inherit the parent's stdout and stderr, otherwise, as you see in the image above, it thinks python is printing to stderr
var util = require('util');
const spawn = require('child_process').spawn;
var run = spawn('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002'],
{ stdio: ['ignore', 'inherit', 'inherit' ] });
run.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

Streaming server issue with gunicorn and flask and Nginx

I am using gunicorn and flask for a web service. I am trying to get my head around running a streaming route (not sure if that is the correct terminology).
my route looks like this:
#app.route('/delay')
def delay():
from time import sleep
def delay_inner():
for i in range(10):
sleep(5)
yield json.dumps({'delay': i})
return Response(delay_inner(), mimetype="text/event-stream")
I expect that the server would yield the output each time that delay_inner does a yield. But, what I am getting is all the json responses at once, and only when the delay_inner finishes execution.
What am I missing here?
--EDIT--
I have fixed the issue for Flask and Gunicorn, I am able to run it as expected by using the flask server, and by going to the Gunicorn port. It streams the data as expected. However, and I should have mentioned this in the original post, I am also running behind nginx. And that is not set up correctly to stream. Can anyone help with that?
You need to turn off the nginx proxy buffering.
location /delay {
proxy_pass http://127.0.0.1:8080;
proxy_buffering off;
}
and reload the config
nginx -s reload

Android HttpPost not working with python CGI server

I'm buliding an android app and need to submit data to my python CGI server. I'm usually pulling data off the server with HttpGet and all those calls work correctly and quickly. When I try to push data with HttpPost, the program hangs indefinitely until I long press the return button on the emulator and force quit the program. The CGI server seems to start the script but doesn't return until I force quit the android app. When the CGI script returns, it says CGI script exited OK but it hasn't done anything.
At the moment I'm executing the request in the UI thread. I know it should be done in an AsyncTask but I want a solution before a try a good solution.
I've spent 3 days trying different things and looking at forums with no luck. I'd really appreciate suggestions. Here's the relevant part of my Android code:
private final String serverIP = "10.0.2.2";
HttpClient httpclient = new DefaultHttpClient();
HttpParams params = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 5000);
String URI = "http://"+serverIP+":8000/cgi-bin/test.py?order_submit=0";
HttpPost post = new HttpPost(URI);
List<NameValuePair> kvPairs = new ArrayList<NameValuePair>(2);
kvPairs.add(new BasicNameValuePair("name", "bob"));
kvPairs.add(new BasicNameValuePair("surname", "the builder"));
try {
Log.i(TAG, "Trying to set Entity");
post.setEntity(new UrlEncodedFormEntity(kvPairs, HTTP.UTF_8));
Log.i(TAG, "Trying to Post");
HttpResponse response = httpclient.execute(post);
Log.i(TAG, "execute done");
httpclient.getConnectionManager().closeExpiredConnections();
} catch (ClientProtocolException e) {
Log.e(TAG,e.toString());
} catch (UnsupportedEncodingException e) {
Log.e(TAG,e.toString());
} catch (IOException e) {
Log.e(TAG,e.toString());
}
which outputs the following in LogCat:
INFO/App:(534): Trying to set Entity
INFO/App:(534): Trying to Post
ERROR/App:(534): java.net.SocketTimeoutException: The operation timed out
My Python CGI server script is as follows:
import os, sys, cgi, csv
import cgitb #CGI error backtracer
cgitb.enable()
form = cgi.FieldStorage()
if "order_submit" in form:
ofile = open(os.getcwd() + "/Forms/Output/foo.csv", "wb")
writer = csv.writer(ofile, delimiter=',', quotechar='"',quoting=csv.QUOTE_ALL)
writer.writerow(["Name", form["name"].value])
writer.writerow(["Surname", form["surname"].value])
ofile.close()
After the Android app request has timed out, foo.csv still does not exist. The same is true even if the if part of the script contains the following, and doesn't use the CGI form at all:
if "order_submit" in form:
ofile = open(os.getcwd() + "/Forms/Output/foo.csv", "wb")
writer = csv.writer(ofile, delimiter=',', quotechar='"',quoting=csv.QUOTE_ALL)
writer.writerow(["Name", "harry"])
ofile.close()
After the httpclient.execute(post); , this is the order of events:
App: httpclient.execute(post);
CGI server: POST /cgi-bin/test.py?order_submit=0 HTTP/1.1" 200
CGI server: starts the 2nd python script
a few second's waiting...
App: java.net.SocketTimeoutException: The operation timed out
Python Script: creates the correct dummy file
CGI server: CGI script exited OK
The error sounds like the given IP is not reachable or port 8000 is blocked by the ISP or firewalled.
I changed
HttpClient httpclient = new DefaultHttpClient();
HttpParams params = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 5000);
to
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, timeout);
HttpConnectionParams.setSoTimeout(params, timeout);
HttpClient httpclient = new DefaultHttpClient(params);
and it works fine now. I don't think I changed anything else. The BasicHttpParams must initialise something that the DefaultHttpClient doesn't, which is strange because the way I've been doing it works fine for HttpGet.

Categories