I tried to use xmlHttpRequest POST to upload file in Meteor project. With Django REST framework 2.3.14.
I used:
var file = $('#control_import_file')[0].files[0];
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.onreadystatechange = function (e) {
if (e.target.status == 200) {
var resp = JSON.parse(e.target.response);
if (resp.status == 'success') {
alert("success");
} else {
alert("fail");
}
}
};
xmlHttpRequest.onload = function () {};
xmlHttpRequest.open("POST", "http://mydemosite.net/orders/import-coupon/25/", true);
if (window.FormData) {
var formData = new FormData();
formData.append("datafile", file);
xmlHttpRequest.send(formData);
}
In Chrome, it returns:
Event {isTrusted: true, type: "readystatechange", target:
XMLHttpRequest, currentTarget: XMLHttpRequest, eventPhase: 2…}
So I can easyly get Json string: target.response object:
""{"status": "error", "data": {"error_data": ["test123"],
"error_code": 0, "error_msg": "Check failed"}, "error_data":
["test123"], "error_code": 0, "error_msg": "Check failed"}"
JSON.parse(e.target.response); --> get sth I want.
However in Firefox: it returns all that json string above in HTML format:
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta name="robots" content="NONE,NOARCHIVE"...</html>
Anyone can help me how to handle error response in Firefox? Or Is there any way to get response in all browsers?
Thanks a lot!
Django Rest Framwork checks the "Accept" header to define if he must return HTML, JSON, CSV or any other format that he can render (cf: http://www.django-rest-framework.org/api-guide/renderers/)
since you are manually using XMLHttpRequest, try adding the accept header with setRequestHeader. Something like:
xmlHttpRequest.setRequestHeader("Accept","application/json");
check in your console that you are passing the correct headers on Chrome and Firefox
Hope this helps
I'm using the Microsoft Cognitive Computer Vision API (the thumbnails function).
I'm trying to use JavaScript and I cannot make sense of the response.
My entire HTML document with embedded JS code is as follows:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</head>
<body>
<button id="btn">Click here</button>
<p id="response">
<script type="text/javascript">
$('#btn').click(function () {
$.ajax({
url: "https://api.projectoxford.ai/vision/v1.0/generateThumbnail?width=100&height=100&smartCropping=true",
beforeSend: function (xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/json");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", "382f5abd65f74494935027f65a41a4bc");
},
type: "POST",
data: '{"url": "https://oxfordportal.blob.core.windows.net/emotion/recognition1.jpg"}'
})
.done(function (response) {
$("#response").text(response);
})
.fail(function (error) {
$("#response").text(error);
});
});
</script>
</body>
</html>
The response I'm getting does not appear to be JSON, it look like this:
How can I work with the response from this API such that I get the image as a base 64 string that I can set to be the src on an image element.
It will end up being something like this but I do not know how to get the <base64string> bit.
<img src="data:image/png;base64,<base64string>">
I've tried everything in the api test console at https://dev.projectoxford.ai/docs/services/56f91f2d778daf23d8ec6739/operations/56f91f2e778daf14a499e1fb/console and it seems to work fine.
I think the problem is that jQuery converts the argument passed to .done into a string – not sure how to stop it doing that. You could try converting that string back to a binary object but that doesn't feel right or you could work out how to get the raw response from jQuery.
I tried this using XMLHttpRequest (which works):
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.response, typeof this.response);
var response = document.querySelector('#response');
var img = new Image();
var url = window.URL || window.webkitURL;
img.src = url.createObjectURL(this.response);
response.appendChild(img);
}
}
xhr.open('POST', 'https://api.projectoxford.ai/vision/v1.0/generateThumbnail?width=5&height=5&smartCropping=true');
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Ocp-Apim-Subscription-Key", "382f5abd65f74494935027f65a41a4bc");
xhr.responseType = 'blob';
xhr.send('{"url": "https://oxfordportal.blob.core.windows.net/emotion/recognition1.jpg"}');
The response from the service is a binary JPEG image, indicated by the response header "Content-Type: image/jpeg".
For advice on how to encode this as base64, and display it, you could look to these related answers:
Base64 encoding
Displaying an image from a web-service
I have used ember-plupload for uploading the images.Now I have written a component for this.I am able to open and select the images from my machine.But I am lost what to do next.I have to send the post request to my server endpoint with body params { photo_file: image file }.My code is following.
component.hbs
{{#pl-uploader extensions="jpg jpeg png gif" for="upload-image" onfileadd="uploadImage" as |queue features|}}
<div class="dropzone" id={{dropzone.id}}>
<a id="upload-image">Add an Image.</a>
</div>
{{/pl-uploader}}
component.js
actions:{
uploadImage:function(file){
console.log(file)
let filename = file.get('name');
file.read().then(function (url) {
console.log(filename)
console.log(url)
}
}
I am able to get the file name and encode base64 value.But not sure how to send the request to server endpoint.
http://example.com/api/addphoto and it require body with parameter photo_file and choosed file.
I am able to make the correct request from postman app.In the body of the request ,I am selecting the file option and it directly gives me the option to choose a file from there itself.The request is made successfully and photo gets added to endpoint when I select an image and send request
How should I do it in my app?
You could use an XMLHttpRequest
uploadImage:function(files){
var file = files[0];
var request = new XMLHttpRequest();
request.open('post', "target url", true);
var formData = new FormData();
var fieldName = 'file';
formData.append(fieldName, file);
request.onreadystatechange = Ember.run.bind(this, function () {
if (request.readyState === 4 && request.status !== 0) {
//success
}
});
request.send(formData);
}
How can you set the Content-Type header to "application/x-www-form-urlencoded; charset=UTF-8" using JavaScript?
I need to do this so I can view a form with french characters without generating errors.
Thanks
Headers are set by the server delivering the content-type as part of the HTTP message. By the time it's in the browser and running the javascript it's too late. Do you have access to the server-side code? Why not set the content type to utf-8 in there? You can also do it as part of the meta tag in the head.
You can add a meta tag into the head of the page, or send the header server-side.
example,
<meta http-equiv="Content-type" content="application/x-www-form-urlencoded; charset=UTF-8"/>
on the server-side, say PHP:
<?php
header( 'Content-type: application/x-www-form-urlencoded; charset=UTF-8' );
?>
that's it!
The content type is set by the server before it sends the HTML to the browser. You can't modify it with JavaScript.
I assume that you want to communicate with the server, for example, to submit a form, and then the server sends you back the results, in which you need the correct Content-type to allow the server to communicate.
if so, then XMLHttpRequest.setRequestHeader() may help.
an example
(
() => {
const form = document.forms.namedItem("my-query-form")
form.addEventListener('submit', function (submitEvent) {
const outputElement = document.getElementById("msg")
const xhr = new XMLHttpRequest();
xhr.open("POST", "query", true);
xhr.setRequestHeader("Content-Type", "application/json"); // <----
xhr.onload = function (oEvent) {
if (xhr.status === 200) {
outputElement.innerHTML = `<p style="color:green;">${xhr.responseText}</p>`;
setTimeout(function () {
window.location.href = "/home";
}, 1000);
} else {
outputElement.innerHTML = `<p style="color:red;">Error ${xhr.status}: ${xhr.responseText}</p>`
}
};
const htmlFormControlsCollection = submitEvent.target.elements
const jsonData = JSON.stringify(
{
"username": htmlFormControlsCollection["username"].value,
});
xhr.send(jsonData);
submitEvent.preventDefault();
}, false);
}
)()
I want to reload an image on a page if it has been updated on the server. In other questions it has been suggested to do something like
newImage.src = "http://localhost/image.jpg?" + new Date().getTime();
to force the image to be re-loaded, but that means that it will get downloaded again even if it really hasn't changed.
Is there any Javascript code that will cause a new request for the same image to be generated with a proper If-Modified-Since header so the image will only be downloaded if it has actually changed?
UPDATE: I'm still confused: if I just request the typical URL, I'll get the locally cached copy. (unless I make the server mark it as not cacheable, but I don't want to do that because the whole idea is to not re-download it unless it really changes.) if I change the URL, I'll always re-download, because the point of the new URL is to break the cache. So how do I get the in-between behavior I want, i.e. download the file only if it doesn't match the locally cached copy?
Javascript can't listen for an event on the server. Instead, you could employ some form of long-polling, or sequential calls to the server to see if the image has been changed.
You should have a look at the xhr.setRequestHeader() method. It's a method of any XMLHttpRequest object, and can be used to set headers on your Ajax queries. In jQuery, you can easily add a beforeSend property to your ajax object and set up some headers there.
That being said, caching with Ajax can be tricky. You might want to have a look at this thread on Google Groups, as there's a few issues involved with trying to override a browser's caching mechanisms. You'll need to ensure that your server is returning the proper cache control headers in order to be able to get something like this to work.
One way of doing this is to user server-sent events to have the server push a notification whenever the image has been changed. For this you need a server-side script that will periodically check for the image having been notified. The server-side script below ensures that the server sends an event at least once every (approximately) 60 seconds to prevent timeouts and the client-side HTML handles navigation away from and to the page:
sse.py
#!/usr/bin/env python3
import time
import os.path
print("Content-Type: text/event-stream\n\n", end="")
IMG_PATH = 'image.jpg'
modified_time = os.path.getmtime(IMG_PATH)
seconds_since_last_send = 0
while True:
time.sleep(1)
new_modified_time = os.path.getmtime(IMG_PATH)
if new_modified_time != modified_time:
modified_time = new_modified_time
print('data: changed\n\n', end="", flush=True)
seconds_since_last_send = 0
else:
seconds_since_last_send += 1
if seconds_since_last_send == 60:
print('data: keep-alive\n\n', end="", flush=True)
seconds_since_last_send = 0
And then your HTML would include some JavaScript code:
sse.html
<html>
<head>
<meta charset="UTF-8">
<title>Server-sent events demo</title>
</head>
<body>
<img id="img" src="image.jpg">
<script>
const img = document.getElementById('img');
let evtSource = null;
function setup_sse()
{
console.log('Creating new EventSource.');
evtSource = new EventSource('sse.py');
evtSource.onopen = function() {
console.log('Connection to server opened.');
};
// if we navigate away from this page:
window.onbeforeunload = function() {
console.log('Closing connection.');
evtSource.close();
evtSource = null;
};
evtSource.onmessage = function(e) {
if (e.data == 'changed')
img.src = 'image.jpg?version=' + new Date().getTime();
};
evtSource.onerror = function(err) {
console.error("EventSource failed:", err);
};
}
window.onload = function() {
// if we navigate back to this page:
window.onfocus = function() {
if (!evtSource)
setup_sse();
};
setup_sse(); // first time
};
</script>
</body>
</html>
Here am loading an image, tree.png, as binary data dynamically with AJAX and saving the Last-Modified header. Periodically (every 5 second in the code below). I issue another download request sending backup a If-Modified-Since header using the saved last-modified header. I check to see if data has been returned and re-create the image with the data if present:
<!doctype html>
<html>
<head>
<title>Test</title>
<script>
window.onload = function() {
let image = document.getElementById('img');
var lastModified = ''; // 'Sat, 11 Jun 2022 19:15:43 GMT'
function _arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa( binary );
}
function loadImage()
{
var request = new XMLHttpRequest();
request.open("GET", "tree.png", true);
if (lastModified !== '')
request.setRequestHeader("If-Modified-Since", lastModified);
request.responseType = 'arraybuffer';
request.onload = function(/* oEvent */) {
lastModified = request.getResponseHeader('Last-Modified');
var response = request.response;
if (typeof response !== 'undefined' && response.byteLength !== 0) {
var encoded = _arrayBufferToBase64(response);
image.src = 'data:image/png;base64,' + encoded;
}
window.setTimeout(loadImage, 5000);
};
request.send();
}
loadImage();
};
</script>
</head>
<body>
<img id="img">
</body>
</html>
You can write a server side method which just returns last modified date of the image resource,
Then you just use polling to check for the modified date and then reload if modified date is greater than previous modified date.
pseudo code (ASP.NET)
//server side ajax method
[WebMethod]
public static string GetModifiedDate(string resource)
{
string path = HttpContext.Current.Server.MapPath("~" + resource);
FileInfo f = new FileInfo(path);
return f.LastWriteTimeUtc.ToString("yyyy-dd-MMTHH:mm:ss", CultureInfo.InvariantCulture);//2020-05-12T23:50:21
}
var pollingInterval = 5000;
function getPathFromUrl(url) {
return url.split(/[?#]/)[0];
}
function CheckIfChanged() {
$(".img").each(function (i, e) {
var $e = $(e);
var jqxhr = $.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Default.aspx/GetModifiedDate",
data: "{'resource':'" + getPathFromUrl($e.attr("src")) + "'}"
}).done(function (data, textStatus, jqXHR) {
var dt = jqXHR.responseJSON.d;
var dtCurrent = $e.attr("data-lastwrite");
if (dtCurrent) {
var curDate = new Date(dtCurrent);
var dtLastWrite = new Date(dt);
//refresh if modified date is higher than current date
if (dtLastWrite > curDate) {
$e.attr("src", getPathFromUrl($e.attr("src")) + "?d=" + new Date());//fool browser with date querystring to reload image
}
}
$e.attr("data-lastwrite", dt);
});
}).promise().done(function () {
window.setTimeout(CheckIfChanged, pollingInterval);
});
}
$(document).ready(function () {
window.setTimeout(CheckIfChanged, pollingInterval);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img class="img" src="/img/rick.png" alt="rick" />
If you are going to check whether files has changed on the server you have to make http request from the server for the file time, because there is no other way for your check the file time once page get loaded to the browser.
So that time check script will like
filetimecheck.php
<?php
echo filemtime(string $filename);
?>
Then you can check the file time using your Javascript. BTW I have put jQuery $.get for check the file time.
dusplayimage.php
<img id="badge" src="image.jpg"> />
<script>
var image_time = <?php echo filemtime(string $filename); ?>;
var timerdelay = 5000;
function imageloadFunction(){
$.get("filetimecheck.php", function(data, status){
console.log("Data: " + data + "\nStatus: " + status);
if(image_time < parseInt(data)) {
document.getElementById('yourimage').src = "image.jpg?random="+new Date().getTime();
}
});
setTimeout(imageloadFunction, timerdelay);
}
imageloadFunction();
</script>
You will be using extra call to the server to check the file time which you can't avoid however you can use the time delay to fine-tune the polling time.
Yes, you can customize this behavior. Even with virtually no change to your client code.
So, you will need a ServiceWorker (caniuse 96.59%).
ServiceWorker can proxy your http requests. Also, ServiceWorker has already built-in storage for the cache. If you have not worked with ServiceWorker, then you need to study it in detail.
The idea is the following:
When requesting a picture (in fact, any file), check the cache.
If there is no such picture in the cache, send a request and fill the cache storage with the date of the request and the file.
If the cache contains the required file, then send only the date and path of the file to the special API to the server.
The API returns either the file and modification date at once (if the file was updated), or the response that the file has not changed {"changed": false}.
Then, based on the response, the worker either writes a new file to the cache and resolves the request with the new file, or resolves the request with the old file from the cache.
Here is an example code (not working, but for understanding)
s-worker.js
self.addEventListener('fetch', (event) => {
if (event.request.method !== 'GET') return;
event.respondWith(
(async function () {
const cache = await caches.open('dynamic-v1');
const cachedResponse = await cache.match(event.request);
if (cachedResponse) {
// check if a file on the server has changed
const isChanged = await fetch('...');
if (isChanged) {
// give file, and in the background write to the cache
} else {
// return data
}
return cachedResponse;
} else {
// request data, send from the worker and write to the cache in the background
}
})()
);
});
In any case, look for "ways to cache statics using ServiceWorker" and change the examples for yourself.
WARNING this solution is like taking a hammer to crush a fly
You can use sockets.io to pull information to browser.
In this case you need to monitor image file changes on the server side, and then if change occur emit an event to indicate the file change.
On client (browser) side listen to the event and then then refresh image each time you get the event.
set your image source in a data-src property,
and use javascript to periodicaly set it to the src attribute of that image with a anchor (#) the anchor tag in the url isn't send to the server.
Your webserver (apache / nginx) should respond with a HTTP 304 if the image wasn't changed, or a 200 OK with the new image in the body, if it was
setInterval(function(){
l= document.getElementById('logo');
l.src = l.dataset.src+'#'+ new Date().getTime();
},1000);
<img id="logo" alt="awesome-logo" data-src="https://upload.wikimedia.org/wikipedia/commons/1/11/Test-Logo.svg" />
EDIT
Crhome ignores http cache-control headers, for subsequent image reloads.
but the fetch api woks as expected
fetch('https://upload.wikimedia.org/wikipedia/commons/1/11/Test-Logo.svg', { cache: "no-cache" }).then(console.log);
the no-cache instructs the browser to always revalidate with the server, and if the server responds with 304, use the local cached version.