Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

tcc-it's avatar

Laravel - 301 Moved Permanently (from disk cache)

When I navigate to the URL localhost/changecontrol, I expect the index.blade.php to be loaded, instead I get an empty 200 OK response after a 301 Moved Permanently (from disk cache). The network tab shows this:

changecontrol -> Status Code:301 Moved Permanently (from disk cache)
changecontrol/ -> Status Code:200 OK

The browser automatically adds the trailing slash to the URL, presumably because of the weird 301 error. I've tried different browsers and the same thing happens.

I've also tried all the usual cache clears: route:clear, cache:clear, view:clear.

Route

Route::namespace('ChangeControl')->group(function() {
    Route::group(['prefix' => 'changecontrol'], function() {
        Route::get('', 'ChangeController@index');
        ...
    });
});

Controller

public function index()
{
    return view('changecontrol.index');
}

Path to view

views
    changecontrol
        index.blade.php

I have an identical set up for another system which uses exactly the same structure, route setup etc. and that one is working fine.

If I amend the route to Route::get('index', 'ChangeController@index'); and then navigate to changecontrol/index, the view will load as expected.

So I really don't know what's going wrong? Why does it work for one system and not the other?

Update: If I change the prefixes and the view subfolder to changecontrol2, it works.

0 likes
15 replies
bashy's avatar

Have you tried this?

Route::get('/', 'ChangeController@index');

What does your routes look like? php artisan route:list

tcc-it's avatar

@bashy Yep, I tried that.

Here's a snippet of the route:list

GET|HEAD | changecontrol             | | App\Http\Controllers\ChangeControl\ChangeController@index  | web,auth
POST     | changecontrol/change      | | App\Http\Controllers\ChangeControl\ChangeController@store  | web,auth
GET|HEAD | changecontrol/change/{id} | | App\Http\Controllers\ChangeControl\ChangeController@show   | web,auth
PATCH    | changecontrol/change/{id} | | App\Http\Controllers\ChangeControl\ChangeController@update | web,auth
tcc-it's avatar

Is Laravel caching something that I don't know about? Surely 'changecontrol' is not a reserved name or anything like that?

bashy's avatar

I know there's some issues (or were) about adding a base / URI in a group but you may just have to define it above the group with the actual URI prepended.

bashy's avatar

@Snapey trailing forward slash should work and be the same route though?

bashy's avatar

Omg is this whole thread about the slash being added and the view is working on both?

What a waste of time if that's true. Thought you couldn't see the blade view with the forward slash :|||||||

tcc-it's avatar

@bashy The thread is because I don't want my URL to be 'changecontrol/index'. It should just be 'changecontrol'.

Even if I declare the route outside of the group, I get the same thing:

Route::get('changecontrol', 'ChangeControl\ChangeController@index');

Route::namespace('ChangeControl')->group(function() {
    Route::group(['prefix' => 'changecontrol'], function() {
        Route::get('change/{id}', 'ChangeController@show');

@Snapey Surely if it were the browser caching, it would work fine on another browser? E.g. I've just tried it in Edge, I've definitely never used Edge before on this project.

tcc-it's avatar

Also, if I remove the route for ChangeController@index altogether, I still get the 301 response followed by the empty 200 response. I would expect a 404 if there was no route?

Snapey's avatar

restart your webserver then? The redirect is cached somewhere!

bashy's avatar

Best to test with cURL or something that doesn't cache the response. You can see the headers returned with curl -I https://domain.ext

tcc-it's avatar

@Snapey I did already try restarting the web server. I also tried changing the binding to a different port. I've also never issued a 301 intentionally.

@bashy curl says:

$ curl -I http://192.168.63.16:92/changecontrol
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0   161    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 301 Moved Permanently
Content-Length: 161
Content-Type: text/html; charset=UTF-8
Location: http://192.168.63.16:92/changecontrol/
Server: Microsoft-IIS/10.0
Date: Wed, 21 Feb 2018 08:38:37 GMT
bashy's avatar

IIS ?

I don't know what the problem is.

Snapey's avatar

It will probably be your .htaccess equivalent for IIS

tcc-it's avatar
tcc-it
OP
Best Answer
Level 3

Okay - after taking a closer look at the web.config:

<match url="^(.*)/$" ignoreCase="false" />
<conditions>
     <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
 </conditions>
<action type="Redirect" redirectType="Permanent" url="/{R:1}" />

This particular rule was causing the issue, because I had a folder where it shouldn't have been:

I had a folder public/changecontrol (which was created mistakenly and never removed). The above rule was matching with this and that's why it was redirecting.

Please or to participate in this conversation.