laravel ajax在共享主机上

I have a laravel application which is deployed on my server.

File structure

server
│

└───blog-app
│    │   app
│    │   bootstrap 
│    │   ......
│
└───public_html
    │    blog
    │     │─── index.php
    │

This is what my structure looks like. Up until now everything seemed to work fine, however now I was trying to make an AJAX call to my controller function but it doesn't work as it should have.

Let me explain it by an example,

$.ajax({
     type:'POST',
     url:'{{route('blog.prefetchResults')}}',
     data:'_token = <?php echo csrf_token() ?>',
     success:function(data){
              $("#msg").html(data.msg);
           }
     });

This is my ajax call which goes to the route blog.prefetchResults which points it to a controller that resides in the BlogController. However when I look in the browser console I see this kind of error:

http://mysubdomain.com/blog/prefetchBlogController@prefetchResults 500 (Internal Server Error)

What I can infer from this error is that it does not allow me to access those directories when a client side request is made, this makes me ask a very simple question: How am I supposed to make an AJAX request using laravel if I can't do it this way?

Update(EXample):

Failed to load resource: the server responded with a status of 500 (Internal Server Error)

test.blade.php

@extends('main')
<p>
This is an ajxax test
</p>
<button class="butt">
    click me
</button>
<script>
    $().ready(function(){
        $('butt').on('click',function(){
                $.ajax({
                 type:'GET',
                 url:'{{route('blog.test')}}',
                 success:function(data){
                          $("p").html("somthing");
                       }
                 });
        })
    });
</script>

Web.php

//Test controller
Route::get('blog/test'.'BlogController@test')->name('blog.test');

BlogController

 public function test(){
       return view('test.test')->withMessage('changed');
    }

File structure

File structure

 server
    │

    └───blog-app //Not accessible through client side languages 
    │    │   app->Http->Controllers/BlogController.php
    │    │   resources->views->test->test.blade.php
    │    │  routes->web.php->route defined here
    │
    └───public_html(www folder)// accessible to the client (www.mydomain.com)
        │    blog
        │     │─── index.php
        │

@Alejandro Reply

  • corrected the above problems.
  • Sorry about app->Http->BlogController.php ,it's app->Http->Controllers/BlogController.php.

Note:

  • The public_html directory is the root directory, that is the root point for my mydomain.com.

  • So the other folders such as blog-app is not accessible for the normal users,they can be only accessed by server side languages.

Log File

[2017-01-08 19:23:01] local.ERROR: exception 'ErrorException' with message 
'Trying to get property of non-object' in 
/home/mydomainuser/blogapp/storage/framework/views/af6b0045a9d30a80c19dd552032d46b39ad1cc99.php:1



Next exception 'ErrorException' with message 
'Trying to get property of non-object (View: /home/foodq7y4/blogapp/resources/views/blog/single.blade.php)' in 
/home/mydomainuser/blogapp/storage/framework/views/af6b0045a9d30a80c19dd552032d46b39ad1cc99.php:1

.htaccess

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>

Single.blade.php

 @extends('main')

@section('title', '| Blog')

@section('content')


    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1>Blog</h1>
        </div>
    </div>

    @foreach ($posts as $post)
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h2>{{ ucwords($post->title) }}</h2>
            <h5>Published: {{ date('M j, Y', strtotime($post->created_at)) }}</h5>

            <p>{{ substr(strip_tags($post->body), 0, 250) }}{{ strlen(strip_tags($post->body)) > 250 ? '...' : "" }}</p>

            <a href="{{ route('blog.single', $post->slug) }}" class="btn btn-sm btn-primary">Read More</a>
            <hr>
        </div>
    </div>
    @endforeach

    <div class="row">
        <div class="col-md-12">
            <div class="text-center">
                {!! $posts->links() !!}
            </div>
        </div>
    </div>


@endsection

Have you tried accessing the url directly with your browser? Given that you are getting "500 (Internal Server Error)" I'd begin by inspecting the server logs. Some things, however:

  • You should be calling the element class: $('.butt'), but I guess you got that.

  • You don't need to pass the csrf token for a GET request. Unless you want to do some validation/authorization of your own. For POST requests, Laravel will check the token. You can send it in the HTTP headers with an ajax option headers: {'X-CSRF-TOKEN': '{{ csrf_token() }}'}.

  • If you want to send the data as a plain string, remove the spaces: data:'_token=<?php echo csrf_token() ?>', otherwise the field ends up being set as _token_.

  • However, I think it's better to set the request data as a JS object: {'_token': '{{ csrf_token() }}'}

  • You said your file structure has app->Http->BlogController.php. By default Laravel expects the controllers to be in app/Http/Controllers directory.

  • It looks like the controller returns an html string, so data.msg probably returns undefined. Instead, data is the html string.

Try fixing these things, then comment or edit with follow-up.


Update: From the server logs we found out the problem was in views/blog/single.blade.php. You already figured out it was $posts->links and apparently posts was not an object.

When doing AJAX requests, remember to always return JSON responses using the response()->json() method instead of using views like in your BlogController test() method example.

Also, implement something like LogViewer in your admin panel (if you have any) to see the log file(s) and read the errors that occur. Setting up Bugsnag is not a bad idea either.

In application this is working great. Change your code like this:

1.View part

<p id="response"></p>
        <button class="butt">
            click me
        </button>
        <script>
            $(document).ready(function(){
                $('.butt').on('click',function(){
                    $.ajax({
                        dataType:'HTML',
                        type:'GET',
                        url:'{{route('blog.test')}}',
                        success:function(data){
                            $("#response").html(data);
                        }
                    });
                })
            });
        </script>

2.Controller part

    public function test()
    {
        return \View::make('test.test')->withMessage('changed');
        //or  return view()->withMessage('changed');
    }

And for feature open console click on network after that when you will click on button it will show you red link if there is an error

  1. Click on that link
  2. In the tab list on the top of console find preview (And Server side error will be shown to you).

Good luck

Your Javascript

Sending HTTP requests to the actual routes instead of the named routes worked for me.

$().ready(function(){
    $('.butt').on('click',function(){
            $.ajax({
               method: 'GET',
               dataType:'json',
               url:'/blog/test',
               success: function(data){
                  console.log(typeof(data)) // see Object {}
               }
            });
    })
});

BlogController

A JSON response should be generated for AJAX requests.

public function test(){
   return response()
        ->json(['type' => 'Test', 'message' => 'It works!']);
}

CSRF Protection

Many options here. My personal favorite:

<meta name="csrf-token" content="{{ csrf_token() }}">