Laravel 405 error when passing parameters with Ajax - javascript

I'm pretty new to Laravel, I've been trying to pass parameters to the destroy() action in my controller with Ajax, the action runs as the pictures data gets removed both from the database and the picture from storage as well, however it gives back 405 error in the console for some reason. I've tried multiple solutions posted here, but none has worked unfortunately. The destroy() action works if I'm using it purely with PHP, but I'm trying to learn a bit of Ajax as well, also I'm doing it this way because I want to do it like there are multiple photos on the site at once, and each one has its own delete button, and I want to delete the photo based on which delete button has been pressed.
It says in the response headers that only GET, HEAD allowed.
Any help would be greatly appreciated, and thank you all in advance!
Routes
Route::get('/photos/create/{albumId}', [PhotosController::class, 'create'])->name('photo-create');
Route::post('/photos/store', [PhotosController::class, 'store'])->name('photo-store');
Route::get('/photos/{id}', [PhotosController::class, 'show'])->name('photo-show');
Route::delete('/photos/{id}', [PhotosController::class, 'destroy'])->name('photo-destroy');
Controller
public function destroy($id)
{
$photo = Photo::find($id);
if (Storage::delete('/public/albums/' . $photo->album_id . '/' . $photo->photo ))
{
$photo->delete();
return redirect('/')->with('success', 'Photo deleted successfully');
}
}
Ajax
$(document).on('click', '.deletePhoto', function(e) {
var photo = $(this).val();
$('#deletePhotoId').val(photo);
$('#photoDelete').modal('show');
});
$(document).on('click', '.confirmDelete', function(e) {
var photo = $('#deletePhotoId').val();
$.ajax({
type: "DELETE",
url: "/photos/"+photo,
data: {
_token: '{{ csrf_token() }}',
},
/* success: function(response){
alert(response);
},
error: function(response) {
alert('Error' + response);
} */
})
});
Also if I have added the csrf as in the Laravel documentation like this:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
Then it gave me 419 error no matter where I have placed it.
Here's the error
XHRDELETEhttp://photo-project.test/
[HTTP/1.0 405 Method Not Allowed 61ms]
DELETE
http://photo-project.test/
Status405
Method Not Allowed
VersionHTTP/1.0
Transferred8.43 kB (8.19 kB size)
Referrer Policystrict-origin-when-cross-origin
Allow
GET, HEAD
Cache-Control
no-cache, private
Connection
close
Content-Type
application/json
Date
Sat, 03 Jul 2021 20:21:15 GMT
Server
Apache/2.4.46 (Win64) PHP/7.3.21
X-Powered-By
PHP/7.3.21
Accept
*/*
Accept-Encoding
gzip, deflate
Accept-Language
en-GB,en;q=0.5
Connection
keep-alive
Content-Length
47
Content-Type
application/x-www-form-urlencoded; charset=UTF-8
Cookie
XSRF-TOKEN=eyJpdiI6IlR0bitkaitPMFhhWEdnQ1ZqL1VpTXc9PSIsInZhbHVlIjoibVREOG9JRGpOQjBqZG40QU9vWVJsS2xtT2J3OXZJK3ZjVzNzZHNKNWdQakowK1lMZ1o0RStSQWFzTVFYZ1R5cFEvNjQ2bm9ZNklYbW8xcW54ZVlzOG9sVXJXN1Z3dmU0Lys0UXRWNWZLY29Femxjb2EvS09qM0hzbm9SSndOYXIiLCJtYWMiOiI2MWJlOTc3YWFhY2NkY2VhZGM5YWZhYmE0MjcyYTc5MmRiNmQwMjU0ZmFlZmMxYzEzNTExMGU4ZjlhMTY3OTYwIn0%3D; laravel_session=eyJpdiI6IldCNU9MSHRGbnNJRlEvWDBrMmZzSmc9PSIsInZhbHVlIjoidzhoc0VFajBhZXk2dkFSa2VmNkU2UmVReVZaOFFUeGJPam1pOXI3T3gvR0FFM3crd21SODI1ZWFJZk44UThDM0VjNFdsL2V6bzNvcHk0NG9vQlpoTEtIRlNQOStxaDlvVFUvS01iOEJIUDJzODFyck11ckpZRTRzMHhVYXhHZlYiLCJtYWMiOiI5NGJmMTBlMDhlOWU0OTU4ZDkyZWRhMzlhYzIwNzFkOTAzZWI3M2RjOTEzNzI5NTYyOWFkZWIyOWMyM2E3MmM2In0%3D
Host
photo-project.test
Origin
http://photo-project.test
Referer
http://photo-project.test/albums/12
User-Agent
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
X-Requested-With
XMLHttpRequest
Thank you again if you can help me in any measure as I'm kind of stuck here unfortunately.

Double-check that your photo JS variable actually has a value. If it's null for some reason, then the route being constructed would end up being the 'index' one, "/photos/", which of course does not have a DELETE http method associated with it.
Check your browser Network history to be sure. You'll see the route that it's attempting to hit, and can also double-check that against the results of php artisan route:list.

public function destroy(Request $request, $id){
$photo = Photo::find($id);
if (Storage::delete('/public/albums/' . $photo->album_id . '/' .$photo->photo )){
$photo->delete();
//if request is via ajax
if($request->ajax()){
return response()->json(['status'=>true,'message'=>'Photo Deleted Successfully']);
}
//otherwise redirect
return redirect('/')->with('success', 'Photo deleted successfully');
}
}
On Ajax Side
$(document).on('click', '.deletePhoto', function(e) {
var photo = $(this).val();
$('#deletePhotoId').val(photo);
$('#photoDelete').modal('show');
});
$(document).on('click', '.confirmDelete', function(e) {
var photo = $('#deletePhotoId').val();
$.ajax({
type: "DELETE",
url: "/photos/"+photo,
data: {
_token: '{{ csrf_token() }}',
},
dataType:'JSON',
cache:false,
success: function(response){
if(response.status){
console.log('Action Successfull....');
console.log('Response from server : ', response.message)
}
},
error: function(response) {
alert('Error' + response);
}
})
});
Just check the request type while returning response from server, If it is ajax then return the response data otherwise redirect to the page.

Related

How can I remove the CORB warning?

Chrome was working until version 73. Now it is throwing me a CORB warning and stopping my chrome extension from running.
Here is my ajax jquery code, nothing special
$.ajax({
url: this.url + "api/users",
type: 'get',
data: { account_id: this.account_id(), user_id: this.user_id(), person_id: person_id },
success: function (data) {
//do stuff
}
});
I did notice that if I remove the x-content-type-options header so that it no longer reads "nosniff" I can get some Ajax requests to be returned but not others. Not sure if this means anything but I noticed that the json requests that returned an array worked but others did not.
remove_keys = %w(X-Content-Type-Options)
response.headers.delete_if{|key| remove_keys.include? key}
[{'id' : '123'}] <-worked
{'id' : '123'} <- did not work (not sure if means anything)
Full error from chrome
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://ideas.test/api/users?token=W9BDdoiKcXLWSHXWySnwdCV69jz2y&account_id=3098355&user_id=john%40gmail.com&person_id=21046915&sync=false&new=true with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.
Headers from response
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: x-auth_token
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
Access-Control-Allow-Origin: chrome-extension://mhikhjencpecbhelhjgdcgpdhlhdlhjh
Access-Control-Expose-Headers:
Access-Control-Max-Age: 1728000
Request Headers
Provisional headers are shown
Accept: */*
Origin: chrome-extension://mhikhjencpecbhelhjgdcgpdhlhdlhjh
Referer: https://3.basecamp.com/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36
How can I get the response body to be returned without chrome removing the body due to CORB?
I found a workaround. Might be an overkill for someone, but it took me 15 mins to fix everythiung. In your content script wrap all your ajax calls into a function:
Add ajaxGet function to your content script:
function ajaxGet(data){
return new Promise(function (resolve, reject) {
chrome.runtime.sendMessage({action: 'ajaxGet', data: data}, function (response) {
console.log(response)
if(response&&!response.statusText){//Might need some work here
resolve(response);
} else {
reject(response)
}
});
});
}
And in your background.js add a listener:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request.action=="ajaxGet"){
$.ajax(request.data).then(sendResponse,sendResponse)
return true //telling chrome to wait till your ajax call resolves
}
})
in stead of
$.ajax({
url: this.url + "api/user_boards",
type: 'get',
data: { account_id: this.account_id()}
})
call
ajaxGet({
url: this.url + "api/user_boards",
type: 'get',
data: { account_id: this.account_id()}
}).then(onSuccess, onError) //handle response from here
If you don't want to use jquery in your background.js you can make Xhr call in stead. Something like this:
var data = JSON.stringify(false);
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
sendResponse(this.responseText)
} else {
//handle errors
}
});
xhr.open("GET", request.data.url);
xhr.send(data);
You'll have to work around headers on your own.
It looks like you're putting the CORS headers in the request. You need to put them in the response instead.
Chrome 73 inject some new security. Just try to move your xHTTP requests to your background script with chrome.runtime.sendMessage and get response with SendResponse callback.
In content or popup script replace ajax with :
chrome.runtime.sendMessage(
{ action: "check", data: {/* params for url */}},
// callback with url response
function(response) {
if( response.success ) {
var myDataFromUrl = response.data;
...
} else {
console.log('Error with `check`,', response.data);
}
}
);
From background script:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var url = 'https://mysyte.com/';
if(request.action === 'check' ) {
url = url + 'check'
ajax( url, request.data,
success: function( d ) {
sendResponse({success: true, data: d});
},
error : function( d ) {
sendResponse({success: false, data: d});
}
);
}
});
function ajax( url, params, cbSuccess, cbError ) { ... }
After fixing the CSP & CORS issues, I was still getting the warning on the OPTIONS method call (which is done for cross-domain calls).
I fixed it on the server by setting the content-type for the OPTIONS method call (which doesn't return any data) to "application/octet-stream". No more warnings!

Using Emotion API for Video (Javascript or Ruby)

So I'm working on posting a video to the Emotion API for video and I haven't been able to get a response.
I've been able to get it to work on the Microsoft online console, but when I try to implement it in my Rails app using (1) JavaScript Ajax, or (2) Ruby server-side code, I consistently get various errors.
Here's my code. At first I tried to Ajax way, but I had a suspicion that the API doesn't have CORS enabled. So then I tried Ruby, to no success.
Ruby attempt:
def index
uri = URI('https://api.projectoxford.ai/emotion/v1.0/recognizeinvideo')
uri.query = URI.encode_www_form({
})
data = File.read("./public/mark_zuck.mov")
request = Net::HTTP::Post.new(uri.request_uri)
# Request headers
request['Ocp-Apim-Subscription-Key'] = 'e0ae8aad4c7f4e33b51d776730cff5a9'
# Request body
request.body = data
request.content_type = "video/mov"
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
puts response.body
end
Here's my Ajax attempt:
function CallAPI(apiUrl, apiKey){
console.log("API called");
$(".loading").css("display", "inline-block");
$.ajax({
url: apiUrl,
beforeSend: function (xhrObj) {
xhrObj.setRequestHeader("Content-Type", "application/octet-stream");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apiKey);
},
type: "POST",
data: '{"url": "http://localhost:5000/mark_zuck.mov"}',
processData: false,
success: function(response){
console.log("API success");
ProcessResult(response);
$(".loading").css("display", "none");
console.log(response);
},
error: function(error){
console.log("API failed");
$("#response").text(error.getAllResponseHeaders());
$(".loading").css("display", "none");
console.log(error);
}
})
Yes, I've regenerated my key. This is just to illustrate my point.
So you have to set Content-Type to application/octet-stream if it's a binary file you're sending, like I was.
If you use a url you should set Content-Type to application/json and the url must be publicly available.

400 bad request ajax post request

I'm running into a weird problem, I want to do a POST request in AJAX with the following code:
$('.login-form').on('submit', function(e) {
e.preventDefault(); // to block the behavior from HTML form
$.ajax({
type: "post",
url: "http://localhost:8080/login",
data: JSON.stringify({
username:"lmezkml",
password:"ezaezaeza"
}),
success: function(data, textStatus, jqXHR) {
console.log('success');
},
contentType: "application/json; charset=utf-8",
dataType: 'json'
});
});
Even after following the multiple topics on this problem, i'm still in trouble.
For example, i've tried :
adding dataType: 'json'
adding contentType : "application/json; charset=utf-8"
using XMLHttpRequest()
using $.post
The inspector of Chrome give me :
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/login
Request Method:POST
Status Code:400 Bad Request
**Request Headersview source**
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,fr;q=0.6
Connection:keep-alive
Content-Length:45
Content-Type:application/json; charset=UTF-8
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/login
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
**Request Payloadview source**
{username:lmezkml, password:ezaezaeza}
password: "ezaezaeza"
username: "lmezkml"
**Response Headersview source**
Connection:close
Content-Type:application/json;charset=UTF-8
Date:Wed, 09 Dec 2015 14:39:11 GMT
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
Here is my code from server :
#RequestMapping(value="/login", method=RequestMethod.POST, produces={"application/json"}, consumes={"application/json"})
public ResponseEntity<?> hello(#RequestParam("name") String username, #RequestParam("password") String password) {
System.out.println("username : " + username + " password : " + password);
try {
LdapContext ctx = ActiveDirectory.getConnection(username, password);
ctx.close();
}
catch(Exception e) {
//Failed to authenticate user!
e.printStackTrace();
return new ResponseEntity<>(null, HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(null, HttpStatus.OK);
}
Hope it can help to resolve my problem of 400 bad request.
Thanks in advance.
I think, problem on server.
Try send to server js object, not string, or debug in server.
I've solved my problem thanks to Alex Repeckiy. The real problem was that the data was stored in Body and ive tried to get them by parameter.
If it can help Spring Framework users, i change my function by using #RequestBody instead of #RequestParam.
Thanks !

File upload with blueimp jQuery file upload, doesn't work in IE9

have create an upload functionality with jQuery-file-upload, my upload work in Firefox, Chrome and IE version more than 9.
I have try to force iframe transport, recommended by doc of jQuery-fileupload plugin.
Fileupload do his tasks, but he send an empty object. So, symfony send an error about file.
My upload process work like this: Backbone.js + require.js -> symfony -> rackspace
$(selector).fileupload({
dataType: 'json',
autoUpload: true,
url: 'http://' + IM('site').get('domain') + '/' + window.PadawanSite.envPath + '/upload/adpost/img',
forceIframeTransport: true,
add: function (e, data) {
var id = e.target.id.substring(e.target.id.length - 2),
jqXHR = data.submit()
.success(function (result, textStatus, jqXHR) {
images.push({
id: id,
original: result.publicUrl.original,
large : result.publicUrl.large,
medium : result.publicUrl.medium,
small : result.publicUrl.small
});
})
.error(function (jqXHR, textStatus, errorThrown) {
$('#picture_callback_' + id).removeClass('glyph icon-spinner2 icon-refresh-animate').addClass('glyph-05 icon-x-empty');
})
.complete(function (result, textStatus, jqXHR) {
if (textStatus === "success") {
var ad = IM('ad').toJSON();
ad.images = images;
IM('ad').clear().set(ad);
IM('ad').save(ad);
if (IM('ad').toJSON()) {
$('#adpost_picture_img_' + id).attr("src", result.responseJSON.publicUrl.small);
$('#picture_callback_' + id).removeClass('glyph icon-spinner2 icon-camera icon-x-empty icon-refresh-animate').addClass('glyph-05 icon-v');
$('#adpost_picture_visualize').removeAttr('disabled');
}
}
});
$('#adpost_picture_visualize').attr('disabled', 'disabled');
$('#picture_callback_' + id).removeClass('glyph-05 icon-camera icon-x-empty').addClass('glyph icon-spinner2');
$('#picture_callback_' + id).addClass('icon-refresh-animate');
$('#adpost_picture_name_' + id).empty();
$('#adpost_picture_name_' + id).append(data.files[0].name);
}
});
My request headers, it sent to symfony. But you can see a content-length equal to 0. So it's the problem, but why he do that ?
X-Requested-With: XMLHttpRequest
Host: sjus.local
Request: POST /app_dev.php/upload/adpost/img HTTP/1.1
Cache-Control no-cache
User-Agent Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
Connection Keep-Alive
Referer http://sjus.local/app_dev.php#postad/picture
Accept-Encoding gzip, deflate
Accept-Language en-us
Content-Length 0
Accept */*
This is a know restriction on IE8/9 when you're doing a cross-domain file upload as the plugin's documentation site says.
I faced this problem once, specifically I was getting the "Permission denied" error when the plugin was trying to retrieve the response from the iframe, this was because in my case the site was a subdomain in the same domain as the api. So I was able to use the option "initialIframeSrc" to specify the document.domain to be used in the iframe (lucky me). I did something like this:
dataType: 'text',
forceIframeTransport: true,
initialIframeSrc: "javascript:document.write('<script>document.domain=\"mydomain.com\";</script>')",
This way the plugin was able to retrieve the response from the iframe contents.
Hope this helps.

why I got request payload on ajax request?

I was used to jQuery in my apps and I was doing ajax request like this:
function save_marker(Marker, mRuas, replaceWin)
{
//Save new marker using jQuery Ajax
var mLatLang = Marker.getPosition().toUrlValue(); //get marker position
var myData = {ruas : mRuas, latlang : mLatLang }; //post variables
console.log(replaceWin);
$.ajax({
type: "POST",
url: "maps/map_process.php",
data: myData,
success:function(data){
replaceWin.html(data); //replace info window with new html
Marker.setDraggable(false); //set marker to fixed
Marker.setIcon('img/b.png'); //replace icon
},
error:function (xhr, ajaxOptions, thrownError){
alert(thrownError); //throw any errors
}
});
}
If I take a look on my ajax request in Chrome Developer Tools under Network tab, I see that ruas and latlang were sent like Form Data.
Form Data :
ruas:1234
latlang:-8.459511,115.066144
Lately I am testing an ajax request like above, I do with :
var dataPath = {
tahun : year,
kawasan : areal,
path : pathSend,
idGenangan : jmlRecord
};
$.ajax({
url :'maps/modul/genangan-sql-drawing.php',
type :'POST',
dataType:'json',
data : JSON.stringify(dataPath),
contentType:"application/json",
success: function(data, xhr){
alert("Sukses Menggambar Genangan");
},
error:function(xhr, ajaxOptions, thrownError){
alert(thrownError);
}
});
I noticed the difference how the data were sent. In this case data were sent like Request Payload.
**Request Payload**
{"tahun":"2012","kawasan":"Kawasan Genangan 2012","path":[{"lat":-8.240032737708358,"lng":115.11680603027344},{"lat":-8.331082833500302,"lng":114.98222351074219},{"lat":-8.363692651835823,"lng":115.26374816894531}],"idGenangan":1}
**Request Header**
POST /bootstrap/maps/modul/genangan-sql-drawing.php HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 230
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://localhost
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Content-Type: application/json
Referer: http://localhost/bootstrap/area-genangan.php
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,id;q=0.6
The question is :
1. what the different between request payload and form data ?
2. why I got request payload ?
3. if I want to change request payload with form data. what should I do ?
I hope anybody understand what I mean and can help me.

Categories

Resources