简体   繁体   中英

Call web service method on Flask server from javascript

I'm new to frontend development and website development; the goal is to call a webservice method on a server from web interface (client) .

Context

I wrote a Python web service with Flask and I deployed it on my Raspberry Pi . I tested it with ngrok and Postman and it works fine, all the methods do exactly what they have to.
I have also a web server ( Nginx ) running on the Raspberry.
The Python web service is exposed on port 5000 ; Raspberry has IP 192.168.1.4 .
addWord is a POST operation provided my the web service.
Finally, PC and Raspberry are on the same network.

Next step

I want to call a method of the Python web service from a frontend website, a simple HTML page, which I put on my web server.

My code

This is the code of my HTML page:

<head>
  <title>prova insert</title>
</head>

<body>
    <p id='text'></p>
  <script>
        var xhr = new XMLHttpRequest();
        var url = "http://192.168.1.4:5000/addWord";
        xhr.open("POST", url, true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                var json = JSON.parse(xhr.responseText);
                console.log(json.email + ", " + json.password);
                text = document.getElementById("text");
                text.innerHTML = 'Ooooooooooooook';
            }
        };
        var data = JSON.stringify({"ita": "neve", "eng": "snow", "descr": "", "pos":"nome"});
        console.log(data);
        xhr.send(data);
  </script>
</body>

</html>

Flask code:

from flask import Flask
from flask import request
import json

import db_connection

app = Flask(__name__)


@app.route('/test')
def test():
    return "Test succeeded."

@app.route('/vocaboli')
def get_vocaboli():
    voc = connection.get_all_words()

    return json.dumps(voc)

@app.route('/addWord', methods = ['POST'])
def add_word():
    data = request.get_json()

    print(data)
    print(data.get('ita'))

    ita = data.get('ita')
    eng = data.get('eng')

    descr = data.get('descr') # opzionali
    pos = data.get('pos')

    connection.add_word(ita, eng, descr, pos)

    response = dict(correct='ok')
    return json.dumps(response)


if __name__ == '__main__':
    connection = db_connection.DatabaseConnection()
    app.run()

dbconnection.py:

class DatabaseConnection():
        def __init__(self):
                self.mariadb_connection = mariadb.connect(user=user, password=password, database='vocabulary')
                print('Connection succeeded.')

        def get_cursor(self):
                return self.mariadb_connection.cursor()

        def get_all_words(self):
                cursor = self.get_cursor()

                cursor.execute("select * from vocaboli")
                return cursor.fetchall()

        def add_word(self, ita, eng, descr=None, pos=None):
                cursor = self.get_cursor()
                cursor.execute("insert into vocaboli (ita, eng, description, pos) values ('{}', '{}', '{}', '{}')".format(ita, eng, descr, pos))
                self.mariadb_connection.commit()

        def update_description(self, ita, eng, descr=None):
                cursor = self.get_cursor()
                cursor.execute("update vocaboli set description = '{}' where ita = '{}' and eng = '{}'".format(descr, ita, eng))
                self.mariadb_connection.commit()

Output
在此处输入图片说明

I tried also to do POST on http://192.168.1.4/addWord , but it returns a NOT FOUND .


Question
How can I call the web service from the Javascript code in the proper way? Have I to use the ngrok tunnel as URL, or I have to use the IP of the Raspberry?
Have I to use PHP in some way to work on the server side?
As I said, I'm not familiar with Javascript/PHP, probably the answer is straightfoward but I can't figure it out.

By default, the Flask server is only accessible locally. As per the Flask documentation , try specifying host='0.0.0.0' when running your app to make it accessible from other devices in the network:

if __name__ == '__main__':
    connection = db_connection.DatabaseConnection()
    app.run(host='0.0.0.0')

Then try displaying the /test page from a browser on the PC ( http://192.168.1.4:5000/test ).

If that doesn't do the trick, make sure port 5000 is open on your Raspberry Pi.

Edit addressing the CORS policy error:

Try using the flask_cors module to allow CORS:

from flask import Flask
from flask_cors import CORS

...

app = Flask(__name__)
CORS(app)

...

I see couple of things here:

  1. If you are using Nginx then create a upstream for http://localhost:5000 so it can act as reverse proxy and applications is available at http://192.168.1.4 with ssl it would be https://192.168.1.4

  2. If backend and front-end are running on different servers you need to use CORS, this could be on Ngnix / Flask level depending on how you have configured.

  3. You need to tell flask rather the function that you would be working with JSON content-type for that look at link

These steps would sort your issue. Nothing to do with DB if it works using Postman.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM