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
<?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'
]);
}
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)
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');
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
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'
]);
}
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
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}`);
});
Créditos del cover:
Top comments (1)
Great!