we're following a project with 3 docker containers:
- PHP 7.4 (backend, CodeIgniter), which provides APIs
- Next.js 12.1 (frontend)
- nginx 1.19.1
We're trying to set up a live notification system. Here's the backend code:
namespace App\Controllers;
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header("Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Content-Length, Accept-Encoding, Authorization");
header("Content-Type: text/event-stream");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Connection: keep-alive");
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\RESTful\ResourceController;
class SSEtest extends ResourceController {
use ResponseTrait;
protected $format = 'json';
const TIME_TO_SLEEP_IN_SECS = 60;
public function run($id_user) {
while(ob_get_level() > 0) {
ob_end_flush();
}
@ini_set('output_buffering', 'Off');
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
@ob_end_clean();
set_time_limit(0);
ob_start();
$id = 0;
while(true) {
$id++;
$curDate = date(DATE_ISO8601);
$notifications = ['foo', 'bar'];
if( is_array($notifications) ) {
$tot = 0;
foreach($notifications AS $n) {
$tot += $n['num'];
}
$this->sendMsg('msg', ['id' => $id, 'time' => $curDate, 'cnt' => $notifications, 'total' => $tot], $id);
}
else {
$this->sendMsg('ping', ['id' => $id, 'time' => $curDate, 'cnt' => 'ping'], $id);
}
ob_flush();
flush();
if( connection_aborted() ) {
break;
}
sleep(self::TIME_TO_SLEEP_IN_SECS);
}
}
protected function sendMsg($event, $data, $id) {
echo 'event: '.$event.PHP_EOL;
echo 'data: '.json_encode($data).PHP_EOL;
echo 'id: '.$id.PHP_EOL;
//echo 'retry: 1000'.PHP_EOL; // Tempo in ms
//echo 'Time: '.date(DATE_ISO8601).PHP_EOL;
echo PHP_EOL;
}
}
And here's our frontend code in a component:
useEffect(() => {
let isMounted = true
const fetchNotifications = async () => {
if(!!user){
await fetchEventSource(API, {
method: "POST",
headers: {
Accept: "text/event-stream",
},
onopen(res) {
if (res.ok && res.status === 200) {
console.log("Connection made ", res);
}
else if (res.status >= 400 && res.status < 500 && res.status !== 429) {
console.log("Client side error ", res);
}
},
/*
event: ping
data: {"id":1,"time":"2022-05-10T11:32:24+0200","cnt":"ping"}
id: 1
retry: NULL
*/
onmessage(e) {
const parsedData = JSON.parse(e.data);
console.log(e, parsedData);
},
onclose() {
console.log("Connection closed by the server");
},
onerror(err) {
console.log("There was an error from server", err);
},
});
}
}
fetchNotifications()
return () => isMounted = false
}, [])
This is the error message we receive:
There was an error from server TypeError: NetworkError when attempting to fetch resource. index.jsx:60:32
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/foo/bar. (Reason: CORS request did not succeed). Status code: (null).
We suspect the error is due to our nginx configuration:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name localhost;
index index.html index.htm index.debian-default.html index.php;
root /var/www/html/public;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
set $virtualdir "";
set $realdir "";
if ($request_uri ~ ^/([^/]*)/.*$ ) {
set $virtualdir /$1;
}
if (-d "$document_root$virtualdir") {
set $realdir "${virtualdir}";
}
location / {
try_files $uri $uri/ $realdir/index.php?$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass api:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Any idea on how to solve the issue? Thank you!