DEV Community

Cover image for Hablemos de CORS & frontend con vite
Nicolás Danelón
Nicolás Danelón

Posted on • Updated on

Hablemos de CORS & frontend con vite

A menudo me encuentro desarrollando sitios con react o preact. Ultimamente preact es mi favorito, mucho mas rapido y liviano. A veces no es necesario usar un servidor real, estoy dando clases, haciendo una demo o simplemente estoy trabajando sin internet y necesito simular requests a un servidor aunque sea local.

Entonces como quiero probar mi frontend hice un simple archivo php que va a leer lo que le mande por POST y por ahora va a devolver json similar al que me va a dar el servidor real.

(Al final del artículo hay una version node del servidor php)

php -S 127.0.0.1 -t server.php
Enter fullscreen mode Exit fullscreen mode
<?php

$json = file_get_contents('php://input');
$data = json_decode($json, true);

if (!isset($data['username']) || !isset($data['password'])) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Username or password not provided'
    ]);
    exit;
}

if ($data['username'] === 'nicolas' && $data['password'] === 'Correct-h0rse-Battery-staple') {
    echo json_encode([
        'status' => 'success',
        'token' => 'fake_token'
    ]);
} else {
    http_response_code(401);
    echo json_encode([
        'status' => 'error',
        'message' => 'Invalid username or password'
    ]);
}

Enter fullscreen mode Exit fullscreen mode

Uso php porque no tiene dependencias, para una demo alcanza y sobra. Pero este código no funciona. El error que veo en la consola dice:

Response body is not available to scripts (Reason: CORS Failed)
Enter fullscreen mode Exit fullscreen mode

A estas alturas, sobre todo despues de haber leido el titulo, ya sabemos por donde viene el error. Pero qué es CORS?

CORS son las siglas de Cross-Origin Resource Sharing. Es un mecanismo de seguridad que permite especificar quien puede acceder a los recursos del servidor.

Entonces lo unico que tengo que agregar a mi codigo php es un par de headers http, verdad?

<?php

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:5173');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
Enter fullscreen mode Exit fullscreen mode

Mi código sigue sin funcionar! Mi request no llega al servidor, pero por que?

Aparentemetne axios está haciendo un request antes del request POST que tiene el JSON con mis credenciales. A este request se lo conoce como una "preflight request" o solicitud previa. Es un request que tiene el verbo OPTIONS y lo unico que hace es preguntar al servidor que tipos de request se puede hacer. Vamos a modificar nuestros headers y a agregaremos un pequeño if para este nuevo verbo:

// headers
header('Access-Control-Allow-Methods: POST, OPTIONS');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}
// fake login
Enter fullscreen mode Exit fullscreen mode

Ahora si! Ahora funciona! Generalmente los navegadores intentan asegurar la politica "Same origin" que impide que un código JavaScript en un origen (dominio, protocolo o puerto) pueda acceder a recursos en otro origen diferente.

Nuestro código php finalmente quedaría así:

<?php

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: http://localhost:5173'); // CORS
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

$json = file_get_contents('php://input');
$data = json_decode($json, true);

if (!isset($data['username']) || !isset($data['password'])) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Username or password not provided'
    ]);
    exit;
}

if ($data['username'] === 'nicolas' && $data['password'] === 'Correct-h0rse-Battery-staple') {
    echo json_encode([
        'status' => 'success',
        'token' => 'fake_token'
    ]);
} else {
    http_response_code(401);
    echo json_encode([
        'status' => 'error',
        'message' => 'Invalid username or password'
    ]);
}

Enter fullscreen mode Exit fullscreen mode

Es posible que no tengas el interprete de php en tu sistema, acá podés encontrar prácticamente el mismo código en nodejs con express:

pnpm init && pnpm add express body-parser cors
Enter fullscreen mode Exit fullscreen mode
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const app = express();
const port = process.env.PORT || 3000;

app.use(bodyParser.json());
app.use(cors());

app.post("/login", (req, res) => {
  const { username, password } = req.body;

  if (!username || !password) {
    res
      .status(400)
      .json({ status: "error", message: "Username or password not provided" });
    return;
  }

  if (username === "nicolas" && password === "Correct-h0rse-Battery-staple") {
    res.json({ status: "success", token: "fake_token" });
  } else {
    res
      .status(401)
      .json({ status: "error", message: "Invalid username or password" });
  }
});

app.listen(port, () => {
  console.log(`Servidor Node.js ejecutándose en http://localhost:${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Créditos del cover:

Top comments (1)

Collapse
 
phpdevvn profile image
https://yhub.io Download video

Great!