I have problem trying to upload a file via json/ajax and does not look like the file was uploaded. Only name of the file was displayed in the console output.
My html code as shown below.
<form action="/cgi-bin/upload.cgi" method="post" enctype="multipart/form-data" target="upIFrame">
<input type="file" id="uploadFileName" name="uploadFileName" size="30" >
<input type="button" id="upgradeFile" name="upgradeFile" value="Upload" onclick="ul.load()" />
<iframe id="upIFrame" name="upIFrame" src="#" style="display: none;"></iframe>
</form>
the ul.load() is calling this line below and eventually the transfer.ajax code will call
transfer.ajax({
url:'upload.cgi',
data:{filename: ul.filename},
success: success,
error: error,
async: true
});
ul.filename comes from uploadFileName
and transfer.ajax code shown below
transfer = {
ajax: function(p) {
if (p.url.indexOf('/') == -1) {
p.url = '/cgi-bin/' + p.url;
}
p.type = 'POST';
p.contentType = 'application/json';
p.dataType = 'json';
p.cache = false;
if (p.data != undefined) {
p.data = JSON.stringify(p.data);
}
$.ajax(p);
}
};
the result after viewing in Fire Fox is
JSON
filename "file.tgz"
Source
{"filename":"file.tgz"}
Could some tell me what I did wrong or what I missed?
TIA
I modified the code to the following...
var fd = new FormData();
fd.append("filename",ul.filename);
$.ajax({
url: "/cgi-bin/test.cgi",
type: "POST",
data: fd,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
beforeSend : function(xhr){
xhr.setRequestHeader('Content-Disposition', 'form-data; name=\"uploadFileName\"; filename=\"' + ul.filename + '\"');
},
});
and the Request Headers in Fire Fox are as
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Content-Disposition form-data; name="uploadFileName"; filename="test.tgz"
Content-Length 157
Content-Type multipart/form-data; boundary=---------------------------20025277823050
X-Requested-With XMLHttpRequest
but the "Post" display the following
Source
-----------------------------20025277823050 Content-Disposition: form-data; name="filename"
test.tgz -----------------------------20025277823050--
How would I include filename="test.tgz"? what's missing?
TIA
Can you try this,
var fd = new FormData();
fd.append("filename",ul.filename);`enter code here`
$.ajax({
url: "/cgi-bin/test.cgi",
type: "POST",
data: fd,
processData: false,
contentType: false,
beforeSend : function(xhr){
xhr.setRequestHeader('Content-Disposition', 'form-data; name=\"' + ul.filename + '\"; filename=\"' + ul.filename + '\"');
}
});
I think name attribute should be as the file name.
Thanks :).
Related
I have an input to upload an excel file and a hidden input
<input type="file" id="file">
<input type="hidden" id="file_submit">
When I choose file in input type file, I want to set its value to hidden input below and retrieve in AJAX function, then I will reset input file for next upload, prevent ERR_UPLOAD_FILE_CHANGED error.
Here is my code in AJAX:
var formData = new FormData();
formData.append('file', $('#file_submit').val());
$.ajax({
url: "{{ route('admin.handle-import') }}",
headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
method: "POST",
data: formData,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function(res) {
$('file').val(''); //reset input file
}
});
I tried this code to set value for hidden input:
document.getElementById('file').onchange = function() {
$('#file_submit').val($(this).prop('files'));
};
And in my controller, I get by code $request->file;. But it only return "[object FileList]". I really don't know what I have to do now.
Can you give me a solution for this?
Thank you very much
I am trying to upload an image file from a partial view using AJAX but it is returning a Bad Request(400) error. I have searched SO answers but it is not working. Here is my script :
$("#prodImgUpload").change(function() {
var formData = new FormData();
formData.append("file", $("#prodImgUpload")[0].files[0]);
console.log(formData.get("file"));
addAntiForgeryToken(formData);
$.ajax({
type: "POST",
url: "#Url.Action("UploadImage","Product",new{area="admin"})",
data: formData,
processData: false,
contentType: false,
cache: false,
async: false,
success: function(result) {
alert("Image uploaded successfully");
},
error: function(jqXHR, textStatus, errorMessage) {
alert(errorMessage);
}
});
And here is the HTML :
<div class="upload-button">
<div class="label">Upload image</div>
<input asp-for="FileToUpload" id="prodImgUpload" name="FileToUpload"
type="file" accept="image/jpeg, image/png, image/jpg, image/bmp" />
</div>
It never reaches the controller. And remember it is in partial view.
Here's my controller's action :
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult UploadImage(IFormFile file)
{
if (file == null)
return Json(new { success = false, message = "No file uploaded" });
//do something with file.
}
You're not including the antiforgery token with the AJAX request. Reference the documentation for how to handle AJAX request with antiforgery tokens. Essentially, you need to add a header to your AJAX request:
$.ajax({
...
headers: {
"RequestVerificationToken": $('#RequestVerificationToken').val()
},
The value comes from a hidden input added via:
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
#functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="#GetAntiXsrfRequestToken()">
I am working with django server side form to save details in DB.
<form id="form_save_file" enctype="multipart/form-data">
{% csrf_token %}
<label class="control-label col-md-4">File:</label>
<div class="col-md-8">
{{form.fa_file}}
</div>
<label class="control-label col-md-4">Name:</label>
<div class="col-md-8">
{{form.name}}
</div>
</form>
I am using ajax to post request.
$("#form_save_file").submit(function(e) {
$.ajax({
type: "POST",
url: '/url/',
data: $("#form_save_file").serialize(),
contentType: false,
processData: false,
success: function(data){}
});
I have included middleware classes in settings.py
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'request.middleware.RequestMiddleware'
)
When I removed contentType and processData in ajax request, request.FILES is empty in views.py and otherthings are working fine.
contentType option to false is used for multipart/form-data forms that
pass files.
When one sets the contentType option to false, it forces jQuery not to
add a Content-Type header, otherwise, the boundary string will be
missing from it. Also, when submitting files via multi-part/form one
must leave the processData flag set to false, otherwise, jQuery will
try to convert your FormData into a string, which will fail.
To try and fix your issue:
You are using jQuery's .serialize() method which creates a text string
in standard URL-encoded notation.
You need to pass un-encoded data when using "contentType: false".
Try using "new FormData" instead of .serialize():
Source: https://stackoverflow.com/a/20863123/3345051
Revised Code:
$("#form_save_file").submit(function(e) {
e.preventDefault();
var $this = $(this);
var postURL = '/url/';
var formData = new FormData(this);
$.ajax({
type: "POST",
url: postURL,
data: formData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
})
.done(function(response) {
// Do something if POST is successful
})
.fail(function() {
// Do something if POST is unsuccessful
})
})
disabled csrf on particular view with #csrf_exempt decorator and build custom security with a random number/string
I've read that both the csrfmiddlewaretoken and the csrftoken cookie have to be the correct value for a django POST request to succeed (django: csrftoken COOKIE vs. csrfmiddlewaretoken HTML Form value). This is the case for me yet I still get a 403:
In the chrome console:
document.cookie
returns
"csrftoken=Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD"
but
$.get('https://learningdollars.fwd.wf/csrftoken/', function(data){
console.log(data)
token = $.parseHTML(data)[0].value
console.log(token)
$.ajax({
type: "POST",
url: 'https://learningdollars.fwd.wf/confirmemail/',
data: {email: 'gdasu#alumni.stanford.edu', csrfmiddlewaretoken: token},
contentType: "application/json"
})
.done(function(response) {
console.log('done!')
})
.fail(function(error) {
console.log('fail!')
})
})
returns
> Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}
> <input type='hidden' name='csrfmiddlewaretoken' value='Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD' />
> Wt9eeJop5Vb3OmeNTvogegckm1pVM5MD
> POST https://learningdollars.fwd.wf/confirmemail/ 403 (Forbidden)
> fail!
I have
'django.middleware.csrf.CsrfViewMiddleware',
activated in my django middleware.
My root urls.py contains:
url(r'^csrftoken/$', views.get_csrf_token),
url(r'^confirmemail/$', views.confirm_email, name='confirm_email'),
And, my views are:
def get_csrf_token(request):
c = {}
c.update(csrf(request))
print c
return render_to_response('csrf.html', c)
def confirm_email(request):
print 'here'
return JsonResponse({'response': 0})
And by the way, the contents of csrf.html are just the csrftoken (inside an input tag):
{% csrf_token %}
What am I doing wrong?
Well, I found a solution. It was just sending in the data as a URI rather than as json. (I by the way tried specifying dataType: 'json' in the above to no avail.) The following is in the chrome console:
> email = 'gdasu#alumni.stanford.edu'
< "gdasu#alumni.stanford.edu"
> csrftoken = 'L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5'
< "L2MxD1XQIF1Xto5NkzUgGUYiHPyyz3K5"
> $.ajax({
type: "POST",
url: 'https://learningdollars.fwd.wf/confirmemail/',
data: "email="+ encodeURI(email) + "&csrfmiddlewaretoken=" + encodeURI(csrftoken),
success: function(data) { console.log(data); }
})
< Object {response: 1}
Still unsure what I was doing wrong on the json side, but the following is what I tried:
$.ajax({
type: "POST",
url: "https://learningdollars.fwd.wf/confirmemail/",
data: JSON.stringify({ email: email, csrfmiddlewaretoken: csrftoken }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
alert(data);
},
failure: function(errMsg) {
alert(errMsg);
}
});
You can forbid Django CSRF by adding csrf_exempt to tell the view not check csrf token.
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def get_csrf_token(request):
c = {}
c.update(csrf(request))
print c
return render_to_response('csrf.html', c)
#csrf_exempt
def confirm_email(request):
print 'here'
return JsonResponse({'response': 0})
I've been all day trying to make the client send AJAX requests with UTF-8 encoding in FormData() objects. I'm using Sping MVC on the server side, but that doesn't apply in this case, since:
I can POST to the server non-multipart requests, and I can capture the request and see:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
and I also can see the characters encoded OK (á, é, í, ó, ú).
If I POST using AJAX + file upload + FormData, using the following code:
var data = new FormData();
data.append('body', jq("#sp_body").val());
data.append('signature', jq("#sp_signature").val());
data.append('subject', jq("#sp_subject").val());
data.append('email', jq("#sp_email").val());
data.append("file", jq("#sp_file")[0].files[0]);
jq.ajax({
url: contextPath + "/jobs/" + job + "/sendmail",
data: data,
cache: false,
dataType: 'text',
processData: false,
contentType: false,
mimeType: "multipart/form-data",
type: 'POST',
success: function(result){
data = jq.parseJSON(result);
if (data["statusCode"] == "success") {
jq("#save_status").html("Email sent!").show().delay(5000).fadeOut(200);
} else {
jq("#save_status").html(data["errors"]).show().delay(5000).fadeOut(200);
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
Then I capture the request and I see:
Content-Type: multipart/form-data; boundary=---------------------------279972256522979
But no UTF-8 in the header, and the non-latin characters are garbled.
The question is, how can I POST using FormData (since I want to POST strings and a file at the same time), having UTF-8 encoding set?
I've read UTF-8 text is garbled when form is posted as multipart/form-data but that didn't help me.
In your servlet, you have to set the encoding again:
public void extractRequest(HttpServletRequest request) throws Exception {
if (request != null) {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
}
catch (FileUploadException e) {
e.printStackTrace();
}
while (itr.hasNext()) {
FileItem item = itr.next();
if (item.isFormField()) {
String name = item.getFieldName();
String value = item.getString("UTF-8");
...
...
In your html:
<form id="formid" action="<yourpath>" enctype="multipart/form-data"
method="POST" accept-charset="utf-8">
And of course, if you are using a database, same thing has to be set there as well
Do let me know if this helps; otherwise we can look at other areas.