Manejo de Errores HTTP en Cliente y Servidor con PHP
Resumen
De momento nuestra API no nos indica que haya ocurrido un error, solamente nos regresa un código 200 de HTTP que significa que la petición se realizó sin problemas.
Para mejorar nuestra API añadiremos respuestas con los códigos HTTP más comunes:
400 Bad Request: indica que el servidor no puede o no procesa la petición debido a algo que es percibido como un error del cliente
404 Not Found: el servidor no encuentra el recurso solicitado.
500 Internal Server Error: la petición no pudo procesarse por un error del servidor.
Los códigos de estado en HTTP se clasifican en varios tipos:
1xx: Respuestas informativas
2xx: Peticiones correctas
3xx: Redirecciones
4xx: Errores del cliente
5xx: Errores del servidor
Los más comunes:
400 Bad Request: Error en la petición.
401 Unauthorized: Falta iniciar sesión.
403 Forbidden: No se poseeen los permisos necesarios.
404 Not Found: No se ha podido encontrar el recurso.
500 Internal Server error: Usualmente fallo en la aplicación web.
502 Bad Gateway: Error entre la comunicación del servidor web y alguno de los servidores que actúan de proxy.
503 Service Unavailable: Servidor está caido por mantenimiento o está sobrecargado.
504 Gateway Timeout: El servidor actúa como puerta de enlace y no puede obtener una respuesta a tiempo.
Una gran lista de codigos.
En esta pagina puedes encontrar los codigos de error en forma de situaciones con gatos 🐱
https://http.cat/
¿Que cojones es la imagen del niño que sale en los primeros minutos?
Horrible
Obviamente es un error :|
Los códigos de error más útilizados en las API REST son:
200 OK (GET, POST, PUT):La solicitud ha tenido éxito.
201 Created (POST, PUT): La solicitud ha tenido éxito y se ha creado un nuevo recurso como resultado de ello.
301 Moved Permanently (GET, POST, PUT, PATH, DELETE): Este código de respuesta significa que la URI del recurso solicitado ha sido cambiado. Probablemente una nueva URI sea devuelta en la respuesta.
401 Unauthorized (GET, POST, PUT, PATH, DELETE): Es necesario autenticar para obtener la respuesta solicitada. Esta es similar a 403, pero en este caso, autenticación es posible.
404 Not Found (GET, POST, PUT, PATH, DELETE): El servidor no pudo encontrar el contenido solicitado. Este código de respuesta es uno de los más famosos dada su alta ocurrencia en la web.
405 Method Not Allowed (GET, POST, PUT, PATH, DELETE): El método solicitado es conocido por el servidor pero ha sido deshabilitado y no puede ser utilizado.
500 Internal Server Error (GET, POST, PUT, PATH, DELETE): El servidor ha encontrado una situación que no sabe como manejarla.
Más sobre mensajes de error en: Códigos de estado de respuesta HTTP
esa imagen del chicle se ve muy asquerosa D:
De acuerdo
Yo quisiera que Platzi subiera un curso de SOAP.
Estaría muy útil decir que para que funcione hay que quitar la parte de autenticación por tokens, sino siempre va a regresar un 200.
Muy útil y cierto!
¿Se debera a que al no tener un token si se esta haciendo la comunicación y por ello devuelve un 200?
Gracias amigo, estuve buscando mucho algun posible error
Códigos de estado 4XX
Indican que se ha producido un error cuyo responsable es el navegador:
400 (Bad Request), el servidor no es capaz de entender la petición del navegador porque su sintaxis no es correcta.
401 (Unauthorized), el recurso solicitado por el navegador requiere de autenticación. La respuesta incluye una cabecera de tipo WWW-Authenticate para que el navegador pueda iniciar el proceso de autenticación.
402 (Payment Required), este código está reservado para usos futuros.
403 (Forbidden), la petición del navegador es correcta, pero el servidor no puede responder con el recurso solicitado porque se ha denegado el acceso.
404 (Not Found), el servidor no puede encontrar el recurso solicitado por el navegador y no es posible determinar si esta ausencia es temporal o permanente.
405 (Method Not Allowed), el navegador ha utilizado un método (GET, POST, etc.) no permitido por el servidor para obtener ese recurso.
406 (Not Acceptable), el recurso solicitado tiene un formato que en teoría no es aceptable por el navegador, según los valores que ha indicado en la cabecera Accept de la petición.
407 (Proxy Authentication Required), es muy similar al código 401, pero en este caso, el navegador debe autenticarse primero con un proxy.
408 (Request Timeout), el navegador ha tardado demasiado tiempo en realizar su petición y el servidor ya no espera esa petición. No obstante, el navegador puede realizar nuevas peticiones cuando quiera.
409 (Conflict), la petición del navegador no se ha podido completar porque se ha producido un conflicto con el recurso solicitado. El caso más habitual es el de las peticiones de tipo PUT que intentan modificar un recurso que a su vez ya ha sido modificado por otro lado.
410 (Gone), no es posible encontrar el recurso solicitado por el navegador y esta ausencia se considera permanente. Si existe alguna posibilidad de que el recurso vuelva a estar disponible, se debe utilizar el código 404.
411 (Length Required), el servidor rechaza la petición del navegador porque no incluye la cabecera Content-Length adecuada.
412 (Precondition Failed), el servidor no es capaz de cumplir con algunas de las condiciones impuestas por el navegador en su petición.
413 (Request Entity Too Large), la petición del navegador es demasiado grande y por ese motivo el servidor no la procesa.
414 (Request-URI Too Long), la URI de la petición del navegador es demasiado grande y por ese motivo el servidor no la procesa (esta condición se produce en muy raras ocasiones y casi siempre porque el navegador envía como GET una petición que debería ser POST).
415 (Unsupported Media Type), la petición del navegador tiene un formato que no entiende el servidor y por eso no se procesa.
416 (Requested Range Not Satisfiable), el navegador ha solicitado una porción inexistente de un recurso. Este error se produce cuando el navegador descarga por partes un archivo muy grande y calcula mal el tamaño de algún trozo.
417 (Expectation Failed), la petición del navegador no se procesa porque el servidor no es capaz de cumplir con los requerimientos de la cabecera Expect de la petición.
422 (Unprocessable Entity (WebDAV)), la petición del navegador tiene el formato correcto, pero sus contenidos tienen algún error semántico que impide al servidor responder.
423 (Locked (WebDAV)), el recurso solicitado por el navegador no se puede entregar porque está bloqueado.
424 (Failed Dependency (WebDAV)), la petición del navegador ha fallado debido al error de alguna petición anterior (por ejemplo una petición con el método PROPPATCH).
426 (Upgrade Required), el navegador debe cambiar a un protocolo diferente para realizar las peticiones (por ejemplo TLS/1.0).
428 (Precondition Required), el servidor requiere que la petición del navegador sea condicional (este tipo de peticiones evitan los problemas producidos al modificar con PUT un recurso que ha sido modificado por otra parte).
429 (Too Many Requests), el navegador ha realizado demasiadas peticiones en un determinado período de tiempo (se utiliza sobre todo para forzar los límites de consumo de recursos de las APIs).
431 (Request Header Fileds Too Large), el servidor no puede procesar la petición porque una de las cabeceras de la petición es demasiado grande. Este error también se produce cuando la suma del tamaño de todas las peticiones es demasiado grande.
Solicito ayuda :D ----He perdido ya dos veces la evaluación por estas preguntas, ustedes me pueden aclarar estos temas la verdad aquí no encuentro la respuesta
¿Cómo debe informar el servidor acerca de errores ocurridos durante el procesamiento de un pedido?
Respuestas usadas / Cuerpo de la Respuesta - Excepciones
¿A través de qué mecanismo se reciben errores al invocar a una API RESTful?
Respuestas usadas / Callbacks - Excepciones
0.30 del video Codigos de errores
o sera Http_response_code
El mejor sitio para códigos HTTP Jaja:
Mi código en javascript
Para este ejemplo creé una ruta que obtenga el ID de un libro en específico y requiere autenticación. Para eso uso el Middleware de autenticación que tenía antes, el siguiente fragmento de código:
app.get('/books/:id', bookAuthenticator,(req, res)=>{// Si no pasa la validación devuelve un 403 forbidden// Verificamos si el libro no existeif(!books[req.params.id]){// Devolvemos un error 404 si no existereturn res.status(404).json({status:'Not found'})}else{// Devolvemos el libro y estado 200 automáticamente res.json(books[req.params.id])}})
Para hacer más fácil el ejemplo uso Postman que es una herramienta para consumir APIs
Caso 403 Forbidden. Consumir el API sin un método de autenticación
Caso 404 Not Found. Acceder a un libro inexistente
Caso 200 OK. Acceder a un libro existente y con autenticación
HTTP STATUS CODES
1×× Informational
100 Continue
101 Switching Protocols
102 Processing
2×× Success
200 OK
201 Created
202 Accepted
203 Non-authoritative Information
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status
208 Already Reported
226 IM Used
3×× Redirection
300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
307 Temporary Redirect
308 Permanent Redirect
4×× Client Error
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Payload Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
418 I'm a teapot
421 Misdirected Request
422 Unprocessable Entity
423 Locked
424 Failed Dependency
426 Upgrade Required
428 Precondition Required
429 Too Many Requests
431 Request Header Fields Too Large
444 Connection Closed Without Response
451 Unavailable For Legal Reasons
499 Client Closed Request
5×× Server Error
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates
507 Insufficient Storage
508 Loop Detected
510 Not Extended
511 Network Authentication Required
599 Network Connect Timeout Error
como paréntesis, creo que la foto de un niño con la cara desfigurada no aporta en nada, es mas es chocante.
Concuerdo, es algo grotezca y no puse atención a otra cosa jaja
Pues si lo analizas mejor no esta desfigurado, estaba mascando chicle. =)
Código en Python basándome en otros comentarios con mis apuntes y modificaciones:
# Imports#from server_test.common.authimportSECRET_KEYfrom flask importFlask, jsonify, make_response
from flask_restful importResource,Api, abort, request
#from common.authimporttoken_requeredfrom functools import wraps
import jwt, datetime
import hmac, hashlib, time
#SECRET='Sh!! No se lo cuentes a nadie'# Auth by Tokensdef token_requered(f): @wraps(f) def decorated(*args,**kwargs): token = request.headers.get('x-token') # get tokken by header
#token = request.args.get("token") # There is not token
if not token:returnmake_response(jsonify({'message':'Token is missing!'}),403) # Try to decode the token, it will raise error if it's incorrect
try: data = jwt.decode(token, app.config['SECRET_KEY'], algorithms="HS256")except:returnmake_response(jsonify({'message':'Token is invalid!'}),403)returnf(*args,**kwargs)return decorated
# Auth by HMAC'''
def auth_required(func): def wrapper(self):try: hash_api = request.headers.get('X-HASH') # Get the headers
hash_client = hmac.new(key=SECRET.encode(), digestmod=hashlib.sha1) # Set the hash algorithm
hash_client.update(request.headers.get('X-UID').encode()) # Set the UID hash_client.update(request.headers.get('X-TIMESTAMP').encode()) # Set the TIMESTAMP(UNIX) # If hashes are the same, then give access to the functionif hash_api == hash_client.hexdigest():returnfunc(self) # An error occured trying to resolve the values necesarry for the hash
except:returnmake_response('Please authenticate by HMAC on X headers!',401,{'WWW-Autencticate':'Basic reaml="Login Required"'}) # Hashes are not a mach,return an error
returnmake_response('Could not verify your login!',401,{'WWW-Autencticate':'Basic reaml="Login Required"'})return wrapper
'''
# Autentificación vía HTML"""
def auth_required(func): def wrapper(self): # print(request.authorization) # If the authentification is correct, then return the function that it wraps
# If not, then return an error
if request.authorization and request.authorization['username']=='carlos' and request.authorization['password']=='1234':returnfunc(self)returnmake_response('Could not verify your login!',401,{'WWW-Autencticate':'Basic reaml="Login Required"'})return wrapper
"""
# Create app and api
app =Flask(__name__)api =Api(app)app.config['SECRET_KEY']="TopSecret"# Data base
BOOKS={'1':{'isbn':'744586','title':'Cien años de soledad','description':'Lorem insup lol.','autor':'Gabriel Garcia Marquez'},'2':{'isbn':'7894546','title':'De animales a dioses','description':'Lorem insup lol.','autor':'Yuval Noah Harari'}}# Aborts the request and returns an error
def abort_if_book_doesnt_exits(book_id):if book_id not inBOOKS:abort(404, message='El libro con id {} no existe'.format(book_id))# Returns the whole book list
classBookList(Resource): @token_requered
def get(self):returnjsonify({'data':BOOKS}) # Returnsas json in data variables
# Metodo para agregar nuevo libro
@token_requered
def post(self): # Getting the request as json format
json = request.get_json(force=True) # Index to post the newbook index =len(BOOKS)+1 # Putting the newbookin the database
BOOKS.update({'{}'.format(index): json }) # Returining the ID to the user
return'Libro agregado correctamente con ID: '+str(index)# Returns an especific id book
classBook(Resource): @token_requered
def get(self, book_id):abort_if_book_doesnt_exits(book_id)returnmake_response(jsonify(BOOKS[book_id]),200) # Returns a response as json with some info code
@token_requered
def put(self, book_id): # Getting the request as json format
json = request.get_json(force=True) # If the id donesn't exist, then quit
abort_if_book_doesnt_exits(book_id) # Replace the information of the book
BOOKS.update({'{}'.format(book_id): json}) # Return the whole collection
returnjsonify(BOOKS)
@token_requered
def delete(self, book_id):abort_if_book_doesnt_exits(book_id) del BOOKS[book_id]returnjsonify(BOOKS) # returnjsonify({'message':'successful delete'})@app.route('/login')def login(): auth = request.authorization #username and password
# Check the password for now
if auth and auth.password=='1234': # Set the token, by username with expiration time and with the secret key
token = jwt.encode({'user': auth.username,'exp': datetime.datetime.utcnow()+ datetime.timedelta(minutes=30)}, app.config['SECRET_KEY']) # Return the token to the client
returnjsonify({'token': token}) # Error at verification
returnmake_response('Could not verify!',401,{'WWW-Authenticate':'Basic realm="Login Requiered"'})classAuthors(Resource): pass
classGeneres(Resource): pass
classRoot(Resource): def get(self, resource_type): allowed_resource_types =["books","authors","genres"]if resource_type not inallowed_resource_types:abort(400, message="Error 404")# Add resources asREST arquitecture
api.add_resource(BookList,'/books')api.add_resource(Book,'/books/<book_id>') #<> means it's a variable
api.add_resource(Authors,'/authors')api.add_resource(Generes,'/generes')api.add_resource(Root,'/<resource_type>')if __name__ =='__main__': app.run(debug=True)
Curl_getinfo: obtener error en el cliente
http_response_code: informar errores del lado del server
Les dejo el código del cliente con comentarios y con una modificación para poder realizar la petición a través de él con la autenticación por Tokens de Acceso (el token se pasa como segundo argumento despues de la URL al ejecutar el cliente)
<?php
// Preparamos la llamada CURL con el primer argumento pasado por// consola al ejecutar el cliente. $ch =curl_init($argv[1]);// Guardamos el Token de autenticación que será el segundo argumento// pasado por consola al ejecutar el cliente $token =array_key_exists(2, $argv)? $argv[2]:'';// Agregamos una opción a la llamada CURL con el Token de autenticacióncurl_setopt($ch,CURLOPT_HTTPHEADER,["X_Token: {$token}"]);// Agregamos la opciön de retornocurl_setopt($ch,CURLOPT_RETURNTRANSFER,true);// Ejecutamos la llamada CURL $response =curl_exec($ch);// Obtenemos el codigo que devuelve el servidor a la nuestra petición $http_code =curl_getinfo($ch,CURLINFO_HTTP_CODE);// Manejamos los codigos HTTPswitch($http_code){case200: echo 'Todo Bien'.PHP_EOL; echo $response.PHP_EOL;break;case400: echo 'Pedido incorrecto'.PHP_EOL;break;case401: echo 'Fallo de autenticación'.PHP_EOL;break;case404: echo 'Recurso no encontrado'.PHP_EOL;break;case500: echo 'El servidor falló'.PHP_EOL;break;}?>
Saludos Jose! Me ayudaste con una tarea de java en el 6to semestre, no se si recuerdes. Pero aja. Digamos que nos estamos poniendo vergas
Por alguna razón me funciona solo si comento la validación de Token en server.php, de lo contrario cualquier consulta de recursos que no existen me sigue retornando "Todo bien!" en la consola.
Manejo de errores de un servicio REST
En una arquitectura REST tiene que ser factible que al ocurrir un error en las peticiones a un servidor, estas sean comunicadas al cliente, esto sirve para saber donde ha ocurrido el problema. Http tiene su lista errores cuando se utiliza este protocolo
Los códigos de estado en HTTP se clasifican en varios tipos:
1xx: Respuestas informativas
2xx: Peticiones correctas
3xx: Redirecciones
4xx: Errores del cliente
5xx: Errores del servidor
Los más comunes:
400 Bad Request: Error en la petición.
401 Unauthorized: Falta iniciar sesión.
403 Forbidden: No se poseeen los permisos necesarios.
404 Not Found: No se ha podido encontrar el recurso.
500 Internal Server error: Usualmente fallo en la aplicación web.
502 Bad Gateway: Error entre la comunicación del servidor web y alguno de los servidores que actúan de proxy.
503 Service Unavailable: Servidor está caido por mantenimiento o está sobrecargado.
504 Gateway Timeout: El servidor actúa como puerta de enlace y no puede obtener una respuesta a tiempo.
Para ver mas lista de errores
Caso de prueba
Para el caso prueba, se debe lo siguiente:
Del lado del servidor existe una función llamada http_response_code() sirve para Obtener o establecer el código de respuesta HTTP. Este se deberá configurar o colocar al momento que se ejecute una acción en el servidor.
Del lado cliente.php se crea una estructura que se encarga de interpretar las respuesta del servidor y entregar una respuesta más consisa
client.php
<?php// Se indica que la petición viene por la terminal$ch=curl_init($argv[1]);// Se confifura curl para recibir la respuesta al// ejecutar la peticióncurl_setopt($ch,CURLOPT_RETURNTRANSFER,true);//Realiza la peteción recibida por terminal$response=curl_exec($ch);// se optine la respuesta del servidor$httpCode=curl_getinfo($ch,CURLINFO_HTTP_CODE);// estructura para interpretar las respuestas httpswitch($httpCode){case200:echo'Todo bien!';break;case400:echo'Pedido incorrecto';break;case404:echo'Recurso no encontrado';break;case500:echo'El servidor fallo';break;}
server.php
<?phpheader('Content-Type: application/json');//Los recursos disponible, prueba$books=[1=>['titulo'=>'Lo que el viento se llevo','id_autor'=>2,'id_genero'=>2,],2=>['titulo'=>'La Iliada','id_autor'=>1,'id_genero'=>1,],3=>['titulo'=>'La Odisea','id_autor'=>1,'id_genero'=>1,],];// Se define los tipos de recursos disponibles$allowedResourceTypes=['books','authors','genres',];// - Se obtiene de la url el valor resource_type,// Luego verifica que el valor obtenido de// resource_type se verifica que exista//en $allowedResourceType$resourceType=$_GET['resource_type'];if(!in_array($resourceType,$allowedResourceTypes)){// Respuesta del servidorhttp_response_code(400);die;}// Se verifica si en el url que se está enviando// existe un id$resourceId=array_key_exists('resource_id',$_GET)?$_GET['resource_id']:'';$method=$_SERVER['REQUEST_METHOD'];switch(strtoupper($method)){case'GET':if("books"!==$resourceType){// si pregunta por un recurso diferente a libro 404// como aun no se implemente entonceshttp_response_code(404);die;}if(!empty($resourceId)){if(array_key_exists($resourceId,$books)){//Existe el libro con el id indicado entoncesechojson_encode($books[$resourceId]);http_response_code(200);}else{//Sí el id no está asociado a ningun librohttp_response_code(404);}}else{// Si no son ninguno de los anteriores caso entonces// se muestra toda la lista de librosechojson_encode($books);http_response_code(200);}die;break;default:http_response_code(400);break;}