laravel / precognition

Anticipate the outcome of a future HTTP request.
https://laravel.com/docs/precognition
MIT License
130 stars 31 forks source link

Error: Did not receive a Precognition response #32

Closed ashens1 closed 1 year ago

ashens1 commented 1 year ago

Laravel Precognition Plugin Version

0.3.2

Laravel Version

10.8

Plugin

React

Description

The following function is throwing an error:

const validatePrecognitionResponse = (response) => {
    if (response.headers?.precognition !== 'true') {
        throw Error('Did not receive a Precognition response. Ensure you have the Precognition middleware in place for the route.');
    }
};

image

Even though it is present as a header when inspecting the network tab:

image

Steps To Reproduce

Copied React example from Laravel documentation

Slund commented 1 year ago

How does your route look like? Did you make sure to use apply the HandlePrecogntiveRequests middleware like this:

Route::post('submit', [HomeController::class, 'submit'])->middleware([HandlePrecognitiveRequests::class]);
vlradstake commented 1 year ago

Had the same issue, my solution was to expose the headers in config/cors.php

'exposed_headers' => ['precognition', 'precognition-success'],

jessarcher commented 1 year ago

@ashens1 I'm having trouble replicating this one.

What's your web server setup like? I noticed HTTPS on port 3000 and Caddy in your screenshot.

Does the same issue occur with just php artisan serve?

If we can figure out the cause we could look either including the exposed_headers or at least documenting it.

driesvints commented 1 year ago

Closing this issue because it's inactive, already solved, old or not relevant anymore. Feel to open up a new issue if you're still experiencing this.

Hernanarica commented 1 year ago

Tuve el mismo problema, mi solución fue exponer los encabezados enconfig/cors.php

'exposed_headers' => ['precognition', 'precognition-success'],

como llegaste a esa solución?

harriskhalil commented 1 year ago

como llegaste a esa solución?

didnt work for me

kasimi commented 5 months ago

I'm using php artisan serve and had the same issue. Updating the routes cache worked for me: php artisan route:cache (which under the hood updates bootstrap/cache/routes-v7.php)

siarheipashkevich commented 1 month ago

Had the same issue, my solution was to expose the headers in config/cors.php

'exposed_headers' => ['precognition', 'precognition-success'],

@timacdonald @driesvints @jessarcher this is should be documented! because it's not obvious and I spent 1 hour to fix and found this, please add a note about this to the documentation.

timacdonald commented 1 month ago

@siarheipashkevich, I'm thinking this might be related to your other issue.

I am happy for us to try and adjust the defaults cors.php or document it in the Precognition documentation, however I'm not sure how to reproduce the issue so I can see it locally. I seem to be able to configure CORS without needing to touch anything related to the headers.

Could you explain how I could reproduce the issue so I can better understand the problem and the solution?

siarheipashkevich commented 1 month ago

@timacdonald thanks for your response.

I'm using different domains for api and front sides and needed to configure cors.php

In my local environment I'm using Laravel Herd for api site, for example precognition-api.test

For front site I'm using next.js which running on localhost:3001, but I think you can use any bundler (webpack, vite, etc)

And your browser should be opened "by default" without disabling any options/flags for cross-site policies

timacdonald commented 1 month ago

Hey folks, I've spent the morning trying to replicate this issue. I would love some help if you have any ideas how I can see the issue on my machine.

I've created a fresh Laravel Breeze application and configured it with Laravel Precognition.

Using Herd, I have linked both breezy-truth.test and blue-sunrise.test to the same application.

I've made it so that any JS / CSS assets are routed via the Laravel application, just so I can easily configure the CORS stuff in Laravel and not mess around with NGINX config.

I've configured the ASSET_URL=http://blue-sunrise.test.

I access the site via http://breezy-truth.test.

Without any configuration to the cors.php I am able to see the site.

You can see that the HTML is being served at breezy-truth.test while the JS and CSS are being served via blue-sunrise.test.

Screenshot 2024-08-08 at 10 23 04

Here are the following headers returned for each URL. Notice that the only CORS header across all of these is Access-Control-Allow-Origin: *.

GET: http://breezy-truth.test/register

HTTP/1.1 200 OK
Server: nginx/1.25.4
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/8.3.9
Cache-Control: no-cache, private
Date: Thu, 08 Aug 2024 00:22:44 GMT
Link: <http://blue-sunrise.test/build/assets/app-Bsbko5O7.css>; rel="preload"; as="style", <http://blue-sunrise.test/build/assets/app-BzGlVY1o.js>; rel="modulepreload"
Vary: X-Inertia
Access-Control-Allow-Origin: *
Set-Cookie: XSRF-TOKEN=...
Set-Cookie: laravel_session=...
Content-Encoding: gzip
GET: http://blue-sunrise.test/build/assets/app-Bsbko5O7.css

HTTP/1.1 200 OK
Server: nginx/1.25.4
Content-Type: text/css; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/8.3.9
Cache-Control: no-cache, private
Date: Thu, 08 Aug 2024 00:22:44 GMT
Access-Control-Allow-Origin: *
Content-Encoding: gzip
GET: http://blue-sunrise.test/build/assets/app-BzGlVY1o.js

HTTP/1.1 200 OK
Server: nginx/1.25.4
Content-Type: application/javascript; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/8.3.9
Cache-Control: no-cache, private
Date: Thu, 08 Aug 2024 00:22:44 GMT
Access-Control-Allow-Origin: *
Content-Encoding: gzip

The when I trigger a validation error the following request / response occur and the validation error is shown.

Screenshot 2024-08-08 at 10 30 31

Here is my CORS configuration file:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

    'paths' => ['*'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];

I have tested in Firefox and Safari.

Is there anything I can do to better replicate this issue? Any help would be appreciated.

timacdonald commented 1 month ago

Oh, and here is a screenshot showing that the validation request we triggered from the asset served from a different domain than the site's URL.

Screenshot 2024-08-08 at 10 36 36
siarheipashkevich commented 1 month ago

This issue related to the default browser behavior

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers#

When we use cross site requests only default allowed headers can be read from site. In our case Precognition and Precognition-Success are not allowed by default and we expose it manually.

Did you try my example with Laravel and nextjs?