JSON POST on iOS with Flask - javascript

Inside my flask python web program, I save a few parameters in SessionStorage in order to send them back to flask, then save this information as a txt file.
For some reason, everything works flawlessly on PC and Android, couldn't get it to work on iOS devices. it recognizes and saves the sessionStorgae elements before sending, but no txt file is created afterwards (at the end of the app).
Client-side (HTML):
function func()
{
...
$.ajax({
url: "{{ url_for('getInfo', _external=True) }}",
type: 'POST',
dataType: 'json',
contentType: 'application/json;charset=UTF-8',
success: function (response) {
console.log(response);
},
accepts: {
json: 'application/json',
},
data: JSON.stringify(log)
});
return;
...
}
<form id = "myForm" name ="myForm" method="post" action="{{url_for('final')}}" onsubmit="return func()">
Server-side (Flask):
#app.route("/get_info",methods = ['POST'])
def getInfo():
list = request.get_json()
global id
with open(id + '.txt', 'w+') as outfile:
json.dump(list,outfile,indent=2)
return 'OK'
I can't figure out the solution. Also I can't remember if it used to work or not on iOS. trying to run all kinds of tests as I'm writing this. Any help would be much appreciated. Thanks.
If you believe more information is needed, I elaborated in the comments about the overall structure of that HTML page and web program.

Your code in 'DEBUG' mode
#app.route("/get_info",methods = ['POST'])
def getInfo():
list = request.get_json()
global id
file_name = '{}.txt'.format(id)
print('About to write {} to file {}'.format(str(list),file_name))
with open(file_name, 'w+') as outfile:
json.dump(list,outfile,indent=2)
print('Data was written')
return 'OK'

Found an answer for future readers:
iOS puts ajax request in cache. which later on might give empty response, or don't trigger the function at all. you can solve that by adding a few parameters and headers to the ajax request, which will prevent it from happenning:
cache: false,
processData: false,
async: true,
headers: {
"cache-control": "no-cache"
},

Related

Ajax query to ruby server

I tries to make AJAX request to my ruby server from browser, but server throws this error It is in last string on the screenshot..
When I make request from terminal(python) everything is ok. What I do wrong?
My ruby server
require 'sinatra'
require 'json'
post "/" do
request.body.rewind # in case someone already read it
data = JSON.parse request.body.read
"Hello #{data['name']}!"
end
My ajax query
$.ajax({
url: 'http://127.0.0.1:4567/',
type: 'POST',
contentType: "application/json",
data: {"name":"b"}
})
.done(
function(data){
console.log(data);
}
)
You can add sinatra-cross_origin to your Gemfile.
After that, update your Sinatra app to include and configure the cross_origin settings as follows
require 'sinatra'
require 'json'
require 'sinatra/cross_origin'
configure do
enable :cross_origin
end
before do
response.headers['Access-Control-Allow-Origin'] = '*'
end
options "*" do
response.headers["Allow"] = "GET, PUT, POST, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type, Accept, X-User-Email, X-Auth-Token"
response.headers["Access-Control-Allow-Origin"] = "*"
200
end
post "/" do
data = JSON.parse request.body.read
"Hello #{data['name']}!"
end
Then you can make your Ajax request like this.
$.ajax({
url: 'http://127.0.0.1:4567/',
type: 'POST',
crossDomain: true,
contentType: "application/json",
data: '{"name":"b"}',
})
.done(
function(data){
console.log(data);
}
)
The difference here is adding crossDomain: true.
Putting these two together should log the right stuff after the Ajax call.
Note: Here we've added Access-Control-Allow-Origin="*". If you know where your html is deployed and where the server sits, you may prefer to have that set to something specific so that it can't be accessed by any site. If your html is deployed at myapp.whateverdomain.com and you might want your server to have something more like
response.headers["Access-Control-Allow-Origin"] = "https://myapp.whateverdomain.com"
You can read more about CORS configuration here

Javascript API POST Request from URL

Forgive me if I have titled this tread wrong, I don't know the correct terminology.
I have a link with values included, they are: id and environment therefore the url it formatted such ad https://foo.com?id=1234&e=s
With this url I need to take the id and the environment (Stage or production) and create a post body to set a flag as true.
So if e=s (environment = stage) I need post to
https://services-stage.foo.com/api/account//flag
Or if e = p (production)
https://services.foo.com/api/account//flag
Where = the id in the url
With POST body:
{
"type": OptionFlag,
"flag": true //Flag should be set to true
}
My problem is I don't know where to start with my limited javascript knowledge. I have created GET requests form api's in the past but never POST and never with parameters in the URL.
I now understand how to handle the post, however I am still at a loss on how I would get the Id and the environment data from the url to then pass them to the ajax url in the function.
function CustomerId(){
//Function for getting id number from URL
}
function apiEnvironment(){
//Function for getting environment from URL
}
function OptOut(CustomerId, apiEnvironment) {
jQuery.ajax({
type: 'POST',
url: apiEnvironment + '/api/v1/account/' + CustomerId + '/optOut',
dataType: 'json',
contentType: 'application/json; charset=UTF-8',
data : data,
success: {
}
});
}
This Is what I have so far...

App Engine second upload to Blobstore not working

I have a form whose data is asynchronously uploaded to Blobstore. When the upload is completed, the backend page outputs another blobstore.get_upload_url() to use for a second upload.
However, when the second upload is performed, it gives a POST http://localhost:13080/_ah/upload/ah1kZXZ-YXZpc2JlcmdhbW8tMTQ2OTk2MTI5MTQ0OXIiCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGICAgICA_IoLDA 404 (Not Found) error
Here's the code (JS):
$.ajax({
url: upload_url,
data: formData,
contentType: false,
processData: false,
success: function (data) {
upload_url = data.url;
formData = new FormData();
},
async: true,
method: 'POST',
});
Here's the backend:
class InserisciDomandaHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
# ... uploads additional data to Datastore
self.response.headers['Content-Type'] = 'application/json'
obj = {
'url': blobstore.create_upload_url('/upload_photo'),
}
self.response.out.write(json.dumps(obj))
I checked the new url and it is different than the old one. Additionally, the new url seems valid.
Why does it give me a 404 error? Thanks
EDIT:
The url seems valid but, when used both in production and in local, it is not treated as valid by App Engine. So, although it "intuitively" makes sense, it doesn't make sense in practice.

W3C Validator offline on localhost by ajax

I use to programming Brackets text editor and I have already installed W3C validator but it working while I'm online but offine not. I try install https://validator.w3.org/docs/install.html and I running to localhost:8888 but brackets's extension connecting only via ajax (javascript). Is possible send ajax like to original W3C website?
Maintainer of the W3C HTML checker (validator) here. Yes it is possible to send an ajax request to a local instance of the current checker. To use Fetch to do it and get JSON-formatted results back:
var checkerUrl = "http://localhost:8888/?out=json"
fetch(document.location.href)
.then(function(currentDoc) { return currentDoc.text(); })
.then(function(htmlSource) {
fetch(
checkerUrl, {
method: "POST",
mode: "cors",
body: htmlSource,
headers: new Headers({ "Content-Type": "text/html;charset=utf-8" })
})
.then(function(checkerResponse) { return checkerResponse.json(); })
.then(function(jsonOutput) {
console.dir(jsonOutput.messages);
})
});
That shows the basic steps to follow to deliver the request in the way the checker expects:
send a document to the checker as the body of a POST (in this example, the current doc)
tell the checker to format its results as JSON (out=json)
make text/html;charset=utf-8 the media type of the POST body you send to the checker
The checker also supports multipart/form-data for giving it the HTML source to be checked, but giving it the source as a POST body instead is the preferred (and better) way for doing it.
If instead of using fetch() you want to use JQuery $.ajax(…), here’s an example:
var checkerUrl = "http://localhost:8888/?out=json"
$.get(document.location.href,
function(htmlSource)
{
$.ajax({
url: checkerUrl,
type: "POST",
crossDomain: true,
data: htmlSource,
contentType: "text/html;charset=utf-8",
dataType: "json",
success: function (jsonOutput) {
console.dir(jsonOutput.messages);
}
});
});
And if instead of either fetch() or JQuery $.ajax(…) you want to use old-school XHR but it’s not clear how to handle the details in that case, let me know and I can post an example of that too.
In all cases, the .messages JSON output is an array of objects that each contain something like:
firstColumn: 1
lastColumn: 6
lastLine: 4
message: "Unclosed element “span”."
type: "error"
The documentation for the checker JSON format gives more details of the JSON the checker emits.

Django ajaxuploader 400 badrequest error

Submitted.html
The JS is also surrounded by a document.ready function
var uploader = new qq.FileUploader({
action: "{% url 'QCOMLTE:imager' %}",
element: $('#file-uploader')[0],
multiple: true,
onComplete: function(id, fileName, responseJSON) {
if(responseJSON.success) {
alert("success!");
} else {
alert("upload failed!");
}
},
onAllComplete: function(uploads) {
// uploads is an array of maps
// the maps look like this: {file: FileObject, response: JSONServerResponse}
alert("All complete!");
},
params: {
'csrf_token': "{{ csrf_token }}",
'csrf_name': 'csrfmiddlewaretoken',
'csrf_xname': 'X-CSRFToken'
}
});
elsewhere in the html body
<div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
</noscript>
</div>
urls.py
urlpatterns = patterns('',
url(r"^Submitted/$", views.HybridDetailView.as_view(), name='Submitted'),
url(r'^(?P<object_type>\w+)/process/$', views.process, name='process'),
url(r'^(?P<object_type>\w+)/$', views.generic_view, name='generic'),
url("$^", views.head, name='head'),
url("uploader", views.upload, name= 'imager'),
)
views.py
#AjaxFileUploader
def upload(request):
response = {'files': []}
script_dir = os.path.dirname(__file__)
# Loop through our files in the files list uploaded
print('request',request)
print(request.FILES)
for item in request.FILES.getlist('files[]'):
file = UploadedFile(item)
with open(script_dir + '/Excel/' + file.name) as destination:
for chunk in file.chunks():
destination.write(chunk)
response['files'].append(file)
print('appended')
return HttpResponse(json.dumps(response), content_type='application/json')
also contains 'ajaxuploader' in the installed apps list
When I try to submit a file through the button it sends the post call but receives a 400 (BAD REQUEST) Error.
It's not even reaching the python from what I can tell, at least not the view code. It seems to form the request URL correctly
http://localhost:8000/QCOMLTE/uploader?qqfile=powered_by.png
And when you go to the URL it sends a message stating that post calls are only allowed.
This is similar to Default django-ajax-uploader with s3 backend gives MalformedXML error
Except that I'm not using any backends, just trying to grab the file/s and save them to a directory.
UPDATE 8/25/14:
Removed the decorator from the view. This results in the error not being sent. After printing the request it becomes evident that the file is being sent to the GET path instead of the FILE path. I don't know how to change this.
After finding this Need a minimal Django file upload example
I preceded to try and imitate it, to find that the FILE and POST requests were actually going through, unlike the ajax/jquery I was using. The JQuery was
$('#uploadform').submit(function (e){
console.log('submitting')
var data = new FormData($('#uploadform').get(0));
$.ajax({
type: 'POST',
url: "{% url 'QCOMLTE:imager' %}",
data: data,
success: function(data){console.log(data)},
error: function(data){console.log(data)},
cache: false,
processData: false,
contentType: false
});
e.preventDefault()
});
except the type was below URL.
I tried changing it to a $.post request and it was trying to post to the wrong URL then...
So I decided to change it back, and this time put type at the top of the ajax call. It then worked... and still does after much testing.

Categories

Resources