I'm learning AJAX according to MDN tutorial, but when I try the first sample to fetch test.html, local server always response with 404, no matter I use absolute or relative path. I have read other similar questions in stackoverflow, but none of them can solve my problem.
Here is my directory structure and source code:
|--templates
| |--index.html
| |--test.html
|
|--app.py
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>index</title>
</head>
<body>
<button id="ajaxButton" type="button">Make a request</button>
<script>
(function(){
let httpRequest
document.getElementById("ajaxButton").addEventListener('click', makeRequest)
function makeRequest() {
httpRequest = new XMLHttpRequest()
if (!httpRequest) {
alert('Giving up: can not create an XMLHTTP instance')
return false
}
httpRequest.onreadystatechange = alertContents
httpRequest.open('GET', 'test.html', true)
httpRequest.send()
}
function alertContents() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText)
}else {
alert('There was a problem with the request.')
}
}
}
})();
</script>
</body>
</html>
I have tried templates/test.html or put test.html outside templates directory but it always return 404 even though I find the url in console is http://127.0.0.1:5000/templates/test.html, which should be right.
I think I must misunderstand someting about URL and server or it matters with flask?
Just in case, here is app.py:
from flask import Flask, render_template
app = Flask(
__name__,
template_folder='./templates'
)
#app.route('/')
def index():
return render_template('index.html')
You're trying to do requests to test.html, but that route does not exist, you have only defined the / route in your Python code which renders index.html template.
If you want the user to access arbitrary templates (e.g. 127.0.0.1:5000/templates/my-template.html), you can write the following route:
#app.route('/templates/<template_name>')
def view_template(template_name):
return render_template(template_name)
Once you've defined that route, the request to /templates/test.html should be successful:
httpRequest.open('GET', '/templates/test.html', true)
Flask looks for the specified template in templates folder by default when you call render_template.
Related
I'm trying to set up a service on Google App Engine, but am having trouble getting XmlHttp to work consistently with it.
After deploying, the website can be accessed from 2 different urls: service-dot-project.appspot and version-dot-service-dot-project.appspot, and for some reason there is inconsistencies between the two.
Heres some demo code that verifyably causes me trouble.
# routes.py
from flask import render_template
from . import app
#app.route("/test", methods=["GET"])
def test():
return render_template("test.html")
#app.route("/api/test", methods=["GET"])
def api_test():
return "It Works!"
# templates/test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Debug</title>
</head>
<body>
<div id="out"></div>
<button type="button" onclick="run()">
Test the thing.
</button>
<script>
function run() {
let xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = () => {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200)
document.getElementById("out").innerText = xmlHttp.responseText;
}
xmlHttp.open("GET", "/api/test", true);
xmlHttp.send(null);
}
</script>
</body>
</html>
# service.yaml
runtime: python38
service: name
automatic_scaling:
min_idle_instances: 1
instance_class: F4
entrypoint: gunicorn -b :$PORT main:app
env_variables:
...
When I try and press the button on the version url, it works as intended, and "It Works!" gets printed into the div above the button, but on the service url (without the version specified), the page itself loads, but pressing the button causes the request to hang for a few seconds, before printing this to the console:
GET https://service-dot-project.appspot.com/api/test [HTTP/2 404 Not Found 7912ms]
When testing using a local flask debugging environment, the problem does not occur.
Is there something that Google App Engine does that I should know about that may have caused this issue to happen? Is /api a reserved endpoint? The rest of my endpoints works on the service url, its only the api endpoints that break. My only app.before_request method fails with a 403, not a 404, so this cannot be the cause.
if you go to https://console.cloud.google.com/appengine/versions
and select your service that is having troubles, is there some other version that is receiving the traffic instead of your desired version?
Also, try going to the logs, find the entry for the 404, expand it and see which version is throwing that error, under protoPayload > versionId
It seems that the issue is being caused by one of the other services running on our project.
Our default service is defining in its dispatch.yaml
dispatch:
- url: "/api*"
module: otherservice
Which is intercepting all the requests made to myservice-dot-project and redirecting them to otherservice-dot-project
Why this isn't the case for the version url is probably because there is no version of the default service with the same version number.
The fix is to either change the dispatch url of the default service, or change the url of the new service's API endpoints.
Update:
I am using recorder.js to record audio from users and I am able to upload the audio file to my Google Cloud Storage bucket. Submitting the form sends the user to the POST route of my Flask app when I test the app locally. However, it hits the GET route when I run the app on Google AppEngine (flex environment).
I think it has to do with the app.js script using XMLHttpRequest and I tried to change app.js to a form post as described here. However, I am new to JavaScript and can't get this to work.
Here is my form:
<html>
<head>
<title>Recording Form</title>
</head>
<body>
<div id="controls">
<button id="recordButton">Record</button>
<button id="pauseButton" disabled>Pause</button>
<button id="stopButton" disabled>Stop</button>
</div>
<ol id="recordingsList"></ol>
<script type="text/javascript" src="/static/js/recorder.js"></script>
<script type="text/javascript" src="/static/js/app.js"></script>
</body>
</html>
Here is the part of the JavaScript I am trying to change to use a regular form post rather than XMLHttpRequest :
var upload = document.createElement('a');
upload.href="/record";
upload.innerHTML = "Upload";
upload.addEventListener("click", function(event){
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("audio_data",blob, filename);
xhr.open("POST","/record",true);
xhr.send(fd);
})
li.appendChild(document.createTextNode (" "))//add a space in between
li.appendChild(upload)//add the upload link to li
//add the li element to the ol
recordingsList.appendChild(li);
}
Here is my flask app:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, request
app = Flask(__name__)
#app.route('/record', methods=['POST'])
def record_post():
audio_data = request.files['audio_data'].read()
return 'done with POST'
#app.route('/record', methods=['GET'])
def record():
return 'done with GET'
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
Thank you for your help.
The source code of recorder.js is here:
https://github.com/mattdiamond/Recorderjs
A live demo of the recorder.js form is here:
https://addpipe.com/simple-recorderjs-demo/
I found out the issue is that the recorded audio file is not uploaded yet when the speech to text function tries to transcribe it. I am going to set up a pub sub topic/ subscription to wait for the upload to be completed now.
So I have set up app.py, index.js, index.html in appropriate folder as flask suggests. Index.html gets rendered as when app.py runs then index.html runs index.js which grabs input data from user. I am trying to send this input and send it to python where I can call an API, grab data, and work with it however I cannot think of a way to do this.
my app.py:
import os
from flask import Flask, render_template, jsonify, request, redirect
app = Flask(__name__)
# This will run upon entrance
#app.route("/")
def home():
return render_template("index.html")
#app.route("/stock_data")
def get_stock_data():
# called from index.js Plot function
if __name__ == "__main__":
app.run()
and here is my javascript code:
console.log("everythin works fine.")
d3.select("#stocklabelsubmit").on("click", submitted)
function submitted(){
d3.event.preventDefault();
// grab label inputted.
var inputted_label = d3.select("#stockInput").node().value;
d3.select("#stockInput").node().value = "";
Plot(inputted_label);
};
function Plot(input){
var url = "full url"
// when this function is called call /stock_data function!!
// data is what is returned from python
d3.json(url).then(function(data){
})
}
Everything works fine, when I console log inputted_label at the end of function submitted it works. Now I want to send inputted_label variable to /stock_data. Thanks in advance!
var url = "/stock_data"
This needs to be a valid URL, not just the path to the Flask endpoint. That means it must start with "http://" or "https://" and include a domain. For development purposes, "http://localhost/stock_data" will work. If you ever deploy this to a server, you will want to create a configuration file so that the host name can be configured depending on what environment you are running in.
I have recently developed a Python API for a chatbot and made a demo using a quick python script:
s = request.Session()
user_response = None
while True:
chat_response = s.get(url='http://localhost:5000/chat', json={'user_input': user_response}).json()
if chat_response['is_end']:
break
if 'text' in response_json:
print '\t' + response_json['text']
user_response = raw_input()
When the chat route is called I set a unique session key
if 'session_id' not in session:
session['session_id'] = chat_utils.id_generator()
This works great on the command line, the session id is used to keep track of the conversation on the server. However I am trying to implement this in a JavaScript front end. Is there an equivalent to the line
s = request.Session()
Currently I am unable to store session information so the initial question is repeated with a different generated key (see below).
This is generated using BotUI
The call to the API is made using the following code:
function chat(){
botui.action.text({
delay: 1000,
action: {
placeholder: 'User response here'
}
}).then(function (res) {
sendxhr(res, textResponse)
});
}
function sendxhr(user_input, formatter){
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:5000/chat');
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("user_input", user_input);
xhr.onload = function () {
var res = JSON.parse(xhr.responseText)
console.log(res)
formatter(res.text)
}
xhr.send();
}
The API call works but as there is no session each time the chat route starts a new session.
The solution to this is to serve the html. Rather than opening the html locally I added a route to serve static html.
#app.route("/")
def index():
return render_template('index.html')
The javascript is loaded in the html and everything works nicely.
I'm quite newbee on API thing, been reading the documentation here for JAVASCRIPT client but I can't make things work, even on authentication part. I already have the client ID and ClientSecret from PODIO itself.
Basically, I want to get all podio data in a workspace in a JSON format using client side (browser only).
I've downloaded the library here and created an HTML file on my localhost and link the podio-js with following code. Getting this error "podio-js.js:1 Uncaught ReferenceError: require is not defined at podio-js.js:1". Do I need to install something such that loader thing to make this work?
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script type="text/javascript" src="lib/podio-js.js"></script>
<script type="text/javascript">
var podio = new PodioJS({
authType: 'server',
clientId: 'foo',
clientSecret: 'foo'
});
var redirectURL = 'http://localhost/PODIO-JS/podio-js-master/PODIO_CLIENT.html';
// Your request handler (for example in ExpressJS)
var action = function(request, response) {
var authCode = request.query.code;
var errorCode = request.query.error;
podio.isAuthenticated().then(function() {
// Ready to make API calls...
}).catch(function(err) {
if (typeof authCode !== 'undefined') {
podio.getAccessToken(authCode, redirectURL, function(err, response) {
// make API calls here
console.log (responsedata);
});
} else if (typeof errorCode !== 'undefined') {
// a problem occured
console.log(request.query.error_description);
} else {
// start authentication via link or redirect
console.log(podio.getAuthorizationURL(redirectURL));
}
});
</script>
</head>
<body>
</body>
</html>
You can only use the syntax PodioJS = require('podio-js') if you're working in an AMD environment, typically using requirejs.
You're using a good ol' HTML page instead, which means you have to follow the second part of the browser usage section found here: https://github.com/podio/podio-js#browser
From within the podio-js folder:
npm install -g browserify
npm run bundle
and then include dist/podio-js.js using a tag in your HTML page.
Note: once you've bundled the source, you can copy paste the compiled file wherever you want.