I have an issue that appears recently (I don't know what was changed)when trying to upload a file to my server.
With all other GET and POST the site is working ok, but the issue is when I need to upload a file (for which I have an specific function).
My site is built with angularjs and Java Spring as backend.
Here you have the function that is use in the factory to upload a file:
var SaveMethod = function(params, callback){
var result = $q.defer();
var form = new FormData();
var xhr = new XMLHttpRequest;
// Additional POST variables required by the API script
form.append("file", params.files);
xhr.upload.onprogress = callback;
xhr.open('POST', SessionService.apiUrl + '/video/save');
xhr.setRequestHeader("Authorization", 'Bearer ' + SessionService.getToken());
xhr.timeout = result.promise;
xhr.onload = function(e) {
if (xhr.status == 200) {
result.resolve(e.target.response);
}
else {
result.reject(xhr.statusText);
}
};
xhr.send(form);
return result.promise;
};
And this is the controller:
$scope.upload = function(item) {
$scope.values.videosubmitted = true;
$scope.values.object.name = item.name.substr(0, item.name.lastIndexOf('.'));
$scope.values.uploading = true;
var params = {
files: item
};
VideoFactory.Save(params, callback).then(function(response){
response = JSON.parse(response);
$scope.values.uploading = false;
if (response.success) {
$scope.values.object.images = response.data.images;
$scope.values.object.code = response.data.code;
$scope.values.object.source = response.data.source;
$scope.values.object.preview = response.data.preview;
}
else
{
$scope.values.error = true;
$scope.values.errorMessage = response.code;
}
}, function(response){
if (response == null) {
$scope.values.error = true;
$scope.values.errorMessage = "ERROR__SERVER_NON_WORKING";
}
else
{
$scope.values.error = true;
$scope.values.errorMessage = response.code;
}
$scope.values.uploading = false;
});
}
And the view (just in case)
<div class="row" ng-show="!values.videosubmitted">
<div class="col-md-10 no-padding-right">
<div class="dropzone" id="dropbox" callback-fn="upload(video)" file-dropzone="[video/mp4, video/3gpp, video/quicktime, video/x-msvideo, video/x-ms-wmv]"
file="image" file-name="imageFileName" values-max-file-size="9000000000">
<span translate="MODULES.VIDEO.DROPVIDEO"></span>
</div>
</div>
<div class="col-md-2 upload-btn no-padding-left">
<label class="upload-search btn btn-primary no-padding">
<div>
<input type="file" onchange="angular.element(this).scope().upload(this.files[0])"/>
<i class="fa fa-upload"></i>
<span translate="COMMON.FILESEARCH"></span>
</div>
</label>
</div>
</div>
The thing is that after the file is sent to the server, it doesn't matter if I get a successful response from server or not, the page is reloaded and the request is canceled. In some cases, I get the successful response from the server but after that the page is reloaded, and in other cases the request is canceled and the page is refreshed.
I tried with the timeout but it doesn't work.
And this is how it looks like:
The issue was something related to CORS I guess..
The thing was that I was using two domains for the web development, localhost for regular use, and an specific domain for being recognize in social media pages to allow the login buttons.
So I discover that when I was using localhsot everything works ok, but when using the other domain it was not.
It was so weird because the backend responded correctly to the request.
Related
I am trying to send a PUT request through XMLHttpRequest but it return an empty using JS for the front end and nodejs for the backend. while in the network section in the dev tools, it shows that PUT is ok . I have been dealing with this for over 10 days, every iota of support will be highly appreciated. I really need this as I don't know what to do next. It's driving me nuts.
Below is my html
<body>
<form action="location.js" id="myLocation" method="PUT">
<br>
<div>
<label> location </label>
<input id="location" type="text" name="location" required>
</div>
<br>
<div>
<button type=submit>submit</button>
</div>
</form>
<div id="locate">
</div>
GO TO LOGIN
<script src="location.js"> </script>
<script src=""> </script>
</body>
Next is the JS for XMLHttpRequest
var form = document.getElementById('myLocation');
var display = document.getElementById('locate');
form.addEventListener('submit', sendData);
function sendData(e) {
e.preventDefault();
var location = document.getElementById('location').value;
var params = JSON.stringify({
"location": location
});
var val = params;
const XHR = new XMLHttpRequest();
XHR.onload = function () {
var out1 = this.responseText;
display.innerHTML = out1;
console.log(out1);
};
XHR.open('PUT', 'http://localhost:5000/parcel/:id/location', true);
XHR.setRequestHeader('Content-type', 'application/json; charset=utf-8');
XHR.setRequestHeader('Method', 'PUT');
XHR.send(val);
}
Below is the API router for the PUT request:
router.put('/:id/location', async (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, application/json;charset=utf-8");
res.setHeader("Access-Control-Allow-Method", "PUT");
let parcels
try {
const {_id} = req.params.id;
const {location} = req.body.location;
parcels = await parcel.findByIdAndUpdate(_id, location);
res.send(parcels);
} catch (err) {
console.log(err);
if (parcels == null) {
res.send('error nul')
} else{
res.send('unsuccesful')
}
}
});
XHR.open('PUT', 'http://localhost:5000/parcel/:id/location', true);
I think that :id is not right here.
Edit:
:id is a "route parameter". The listener can use it to cover a range of routes.
So if your API gets a GET request on /parcel/0001/location or /parcel/asd/location then the /parcel/:id/location handler can respond to all of them, and you can read the id from req.params.id.
You can only use this feature if you already know :id on the client side, and you can build it into the route e.g: "http://localhost:5000/parcel/"+id+"/location".
Pretty much what the title says. Here's the javascript... Works fine when not validating the token. Doesn't appear to see it when validating as I get The required anti-forgery form field "__RequestVerificationToken" is not present. error.
var downloadEmailSignature = function (control) {
if (control) {
let form = $(control).closest('form');
let token = $(form).find('input[name="__RequestVerificationToken"]').val();
if (form) {
let request = new XMLHttpRequest();
request.open("POST", "Forms/DownloadEmailSignature");
request.responseType = "blob";
request.setRequestHeader('RequestVerificationToken', token);
request.data = form.serialize();
request.onload = function () {
if (window.clientData.browser.name === "Internet Explorer") {
window.navigator.msSaveBlob(this.response, "EmailSignature.hta");
}
else{
let url = window.URL.createObjectURL(this.response);
let a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = this.response.name || "download-" + $.now();
a.click();
}
};
console.dir(request);
request.send();
}
}
};
and the code behind...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult DownloadEmailSignature(string emailSignature)
{
var hta = (MediaItem)SitecoreContext.GetItem<Item>(new Guid("{EE806F14-5BD3-491C-9169-DA701357FB45}"));
using (var reader = new StreamReader(MediaManager.GetMedia(hta).GetStream().Stream))
{
var htaText = reader.ReadToEnd();
htaText = htaText.Replace("*CARDSTRING*", emailSignature);
var stream = new MemoryStream(htaText.ToASCIIByteArray());
return new FileStreamResult(stream, "application/hta");
}
}
And finally the view...
<form id="download-email-signature" method="POST" enctype="multipart/form-data">
#Html.HiddenFor(m => m.EmailSignatureMarkup)
#Html.AntiForgeryToken()
#Html.FormIdentifier("FormsController", "DownloadEmailSignature")
Download installer
</form>
If you can replace XMLHttpRequest with $.ajax (as you already have JQuery loaded), the below segment should work.
let form = $(control).closest('form');
let token = $(form).find('input[name="__RequestVerificationToken"]').val();
$.ajax({
url: '/Home/DownloadEmailSignature',
type: 'POST',
data: {
__RequestVerificationToken: token,
emailSignature: 'emailSignature value'
},
success: function (result) {
alert(result);
//your code ....
}
});
According to the answer here:
ValidateAntiForgeryToken purpose, explanation and example
MVC's anti-forgery support writes a unique value to an HTTP-only
cookie and then the same value is written to the form. When the page
is submitted, an error is raised if the cookie value doesn't match the
form value.
Which implies the cookie MUST go back to the server. This should be working fine unless you are using IE9 (which is known to be problematic with this issue).
I recommend you include request.withCredentials = true; to eliminate any strange CORs related issue.
If a proxy is involved, the cookie may be getting stripped on the way back to the server too.
I'm trying to obtain the details of files that I previewed in my webpage using the <embed src = "full path" I only found the input tag way which doesn't match what I want.
This is my HTML:
<div id="collapse2" class="panel-collapse collapse">
<div class="panel-body" onclick="return myFunction1('0')">Capture.PNG</div>
<div class="panel-body" onclick="return myFunction1('1')">Sample2.PDF</div>
This is my JavaScript:
<script type="text/javascript">
function myFunction1(index) {
var parent = $('#demo').parent();
if (index == '0') {
$('#demo').remove();
$("h2").append("<embed id = 'demo' src='http://localhost:8080//Part2/Capture.PNG' width='500' height='600'>");
}
if (index == '1') {
$('#demo').remove();
$("h2").append("<embed id = 'demo' src='http://localhost:8080//Part2/sample2.pdf' width='500' height='600'>");
}
}
</script>
So basically, after I click on Capture.PNG/sample2.pdf a preview space is displayed in the page showing the content of the file.
You should be able to get all the info available in the File API through an Ajax request, but you would obviously need your file to be hosted on a cross-origin compliant domain:
let url = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
// do a HEAD request so we don't download the whole file
fetch(url, {method: 'head'})
.then(grabFileInfo)
.then(console.log)
.catch(console.error);
function grabFileInfo(response) {
// just in case...
if(!response.ok) {
throw new Error('Error while fetching data');
}
// grab the response headers
let headers = response.headers,
// 'last-modified' should be in a string format
lastModif = new Date(headers.get('last-modified'));
return {
// the name should be in the url
name: response.url.substring(url.lastIndexOf('/')+1),
type: headers.get('content-type'),
lastModified: lastModif.getTime(),
lastModifiedDate: lastModif,
size: +headers.get('content-length')
};
}
Or with the XHR API:
var url = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
var xhr = new XMLHttpRequest();
xhr.onload = grabFileInfo;
xhr.onerror = console.error;
xhr.open('HEAD', url);
xhr.send();
function grabFileInfo(xhrEvent) {
var xhr = xhrEvent.target,
lastModif = new Date(xhr.getResponseHeader('last-modified'));
console.log({
name: xhr.responseURL.substring(url.lastIndexOf('/') + 1),
type: xhr.getResponseHeader('content-type'),
lastModified: lastModif.getTime(),
lastModifiedDate: lastModif,
size: +xhr.getResponseHeader('content-length')
});
}
I have been trying to submit an embedded Mailchimp form with AJAX but without using jQuery. Clearly, I am not doing this properly, as I keep ending up on the "Come, Watson, come! The game is afoot." page :(
Any help with this would be greatly appreciate.
The form action has been altered to replace post?u= with post-json?u= and &c=? has been added to the end of the action string. Here is my js:
document.addEventListener('DOMContentLoaded', function() {
function formMailchimp() {
var elForm = document.getElementById('mc-embedded-subscribe-form'),
elInputName = document.getElementById('mce-NAME'),
elInputEmail = document.getElementById('mce-EMAIL'),
strFormAction = elForm.getAttribute('action');
elForm.addEventListener('submit', function(e) {
var request = new XMLHttpRequest();
request.open('GET', strFormAction, true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = JSON.parse(request.responseText);
request.send(resp);
} else {
console.log('We reached our target server, but it returned an error');
}
};
request.onerror = function() {
console.log('There was a connection error of some sort');
};
});
}
formMailchimp();
});
Also, I anticipate the inevitable "why don't you just use jQuery" comment. Without going into the specifics of this project, jQuery is not something I am able to introduce into the code. Sorry, but this HAS to be vanilla javascript. Compatibility is for very modern browsers only.
Thanks so much for any help you can provide!
A few days back I've had the exact same problem and as it turns out the MailChimp documentation on native JavaScript is pretty sparse. I can share with you my code I came up with. Hope you can build from here!
The simplified HTML form: I've got the from action from the MailChimp form builder and added "post-json"
<div id="newsletter">
<form action="NAME.us1.list-manage.com/subscribe/post-json?u=XXXXXX&id=XXXXXXX">
<input class="email" type="email" value="Enter your email" required />
<input class="submit" type="submit" value="Subscribe" />
</form>
</div>
The JavaScript: The only way to avoid the cross-origin problem is to create a script and append it to the header. The callback occurs then on the “c” parameter. (Please note there is no email address validation on it yet)
function newsletterSubmitted(event) {
event.preventDefault();
this._form = this.querySelector("form");
this._action = this._form.getAttribute("action");
this._input = this._form.querySelector("input.email").value;
document.MC_callback = function(response) {
if(response.result == "success") {
// show success meassage
} else {
// show error message
}
}
// generate script
this._script = document.createElement("script");
this._script.type = "text/javascript";
this._script.src = this._action + "&c=document.MC_callback&EMAIL=" + this._input;
// append script to head
document.getElementsByTagName("head")[0].appendChild(this._script);
}
var newsletter = document.querySelector("#newsletter")
newsletter.addEventListener("submit", newsletterSubmitted);
Basically, I want to have an interactive button on my website, that, when clicked, sends some data to the server in order to be checked and display the response (without form sending / page reload).
I thought it would be something like:
function checkData()
{
var req = new XMLHttpRequest();
var conf = document.getElementById('my_text_area').value;
req.open("GET", 'check_data', true);
req.onreadystatechange = function ()
{
var pre = document.getElementById('check_data_out');
pre.innerHTML = req.responseText;
}
req.send(conf);
return false;
}
And on the server side:
#get('/check_data')
def check_data():
# Process the content and answer something...
content = str(request.is_ajax) + ' - ' + str(request.GET) + ' - ' + str(request.POST)
return content
But this obviously doesn't work. Either it is not the right way to send data via javascript or not the right way to access it in bottle.py.
Showing me how it works is highly appreciated.
You can use dojo for client side logic.
var button = dojo.byId('button_id'); // button_id refers to the id of the button you want to click
dojo.connect(button,'onclick',dojo.xhrGet({
url: '/check_data',
handleAs : 'text',
load : function(response){
dojo.byId('button_id').innerHTML = response;
}
}));