REST peut être utilisé de manière pratique pour la communication de données entre le serveur et le client. En ce qui concerne l'utilisation de REST, il existe des informations sur la création d'un client dans différents langages et frameworks. Cependant, du côté du serveur, il y a des informations telles que comment construire avec "JsonServer" ou Apache + PHP comme une maquette qui peut être facilement préparée, mais c'est une méthode pour accepter les inconvénients ou prendre du temps et des efforts. (Ce sera aussi loin que je pourrai trouver.)
Cette fois, j'ai essayé de créer un serveur qui se trouve au milieu de ce qui précède, ce qui vous permet de définir librement des services et de créer facilement avec un script. (Le but n'est pas d'exiger suffisamment de robustesse pour être publié sur le WEB, mais de créer votre propre service Raspberry Pi.)
C'est un code de ressource en direct.
restserver.py
#!/usr/bin/env python3
import http.server
import json
import threading
import sys,os
import time
class RestHandler(http.server.BaseHTTPRequestHandler):
def do_OPTIONS(self):
#Prend en charge la demande de contrôle en amont
print( "options" )
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
def do_POST(self):
print( "post" )
local_path = self.path.strip("/").split("/")
#Obtenir la demande
content_len = int(self.headers.get("content-length"))
body = json.loads(self.rfile.read(content_len).decode('utf-8'))
#Traitement des réponses
if( local_path[0] == "dat" ):
if(os.path.getsize('./dat.json')):
with open('./dat.json', 'r') as json_open:
json_load = json.load(json_open)
json_load.update(**body)
json_wraite = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
else:
json_wraite = json.dumps(body, sort_keys=False, indent=4, ensure_ascii=False)
with open('./dat.json', 'w') as json_open:
json_open.write(json_wraite)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
return
else:
print( "no" )
print( self.path )
return
def do_GET(self):
print( "get" )
local_path = self.path.strip("/").split("/")
#Traitement des réponses
if( local_path[0] == "dat" ):
print( "dat" )
if(os.path.getsize('./dat.json')):
with open('./dat.json', 'r') as json_open:
json_load = json.load(json_open)
else:
json_load = {}
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
body_json = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
self.wfile.write(body_json.encode("utf-8"))
return
else:
print( "no" )
print( self.path )
return
def do_DELETE(self):
print( "delete" )
local_path = self.path.strip("/").split("/")
if( local_path[0] == "dat" ):
print( "dat" )
with open('./dat.json', 'w') as file_open:
pass
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
return
else:
print( "no" )
print( self.path )
return
def rest_server(port):
httpd_rest = http.server.ThreadingHTTPServer(("", port), RestHandler)
httpd_rest.serve_forever()
def main():
#Démarrage du serveur
port_rest = 3333
try:
t1 = threading.Thread(target=rest_server, args=(port_rest,), daemon = True)
t1.start()
while True: time.sleep(1)
except (KeyboardInterrupt, SystemExit):
print("exit")
sys.exit()
if __name__ == "__main__":
main()
Le serveur HTTP est configuré sur le port 3333 en effectuant une analyse REST avec do_OPTIONS / do_POST / do_GET / do_DELETE de BaseHTTPRequestHandler de Python. L'opération est simple, elle met à jour (POST), récupère le contenu (GET), et initialise (DELETE) le fichier "dat.json" dans le répertoire courant.
REST accepte généralement les quatre types de requêtes suivants.
Il devrait être créé en fonction de cela, mais j'ai décidé de ne pas préparer PUT car POST peut être utilisé comme substitut.
Pour les "OPTIONS" qui ne sont pas incluses dans les 4 types, en fonction des spécifications du navigateur, une demande OPTIONS sera émise avant la demande POST. Le "Access-Control-Allow-Methods" inclus dans l'en-tête de la réponse à cette requête OPTIONS décrit les méthodes que le serveur peut gérer et si POST est inclus, la requête POST est émise suite à la requête OPTIONS. Je vais. Cette opération s'appelle le contrôle en amont et il s'agit d'une opération de navigateur, il existe donc des solutions de contournement telles que la demande du côté serveur, mais si vous préparez votre propre serveur, il est plus facile de prendre en charge la requête OPTIONS, alors rendez-la compatible. J'ai fait.
Je vais expliquer chaque volume. do_OPTIONS
do_OPTIONS
def do_OPTIONS(self):
#Prend en charge la demande de contrôle en amont
print( "options" )
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
Créez une réponse à la requête OPTIONS décrite dans la section précédente. Il renvoie simplement une réponse.
do_POST
do_POST
def do_POST(self):
print( "post" )
local_path = self.path.strip("/").split("/")
#Obtenir la demande
content_len = int(self.headers.get("content-length"))
body = json.loads(self.rfile.read(content_len).decode('utf-8'))
#Traitement des réponses
if( local_path[0] == "dat" ):
if(os.path.getsize('./dat.json')):
with open('./dat.json', 'r') as json_open:
json_load = json.load(json_open)
json_load.update(**body)
json_wraite = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
else:
json_wraite = json.dumps(body, sort_keys=False, indent=4, ensure_ascii=False)
with open('./dat.json', 'w') as json_open:
json_open.write(json_wraite)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
return
else:
print( "no" )
print( self.path )
return
Le processus POST écrit les données JSON reçues dans la demande POST dans un fichier. Nous suivrons le processus dans l'ordre du haut.
local_path = self.path.strip("/").split("/")
self.path contient les données URL de la requête. Divisez ceci par "/" et conservez-le dans le tableau. Par exemple, si la requête est "nom_serveur / aaa / bbb / ccc /", le chemin_local sera comme suit. local_path[0]='aaa' local_path[1]='bbb' local_path[2]='ccc'
content_len = int(self.headers.get("content-length"))
body = json.loads(self.rfile.read(content_len).decode('utf-8'))
C'est un processus pour analyser les données json reçues avec la demande et les stocker dans les données de type dictionnaire.
#Traitement des réponses
if( local_path[0] == "dat" ):
if(os.path.getsize('./dat.json')):
with open('./dat.json', 'r') as json_open:
json_load = json.load(json_open)
json_load.update(**body)
json_wraite = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
else:
json_wraite = json.dumps(body, sort_keys=False, indent=4, ensure_ascii=False)
with open('./dat.json', 'w') as json_open:
json_open.write(json_wraite)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
return
Dans l'étape suivante, nous vérifierons local_path [0] et définirons l'API si c'est "dat". Dans l'exemple, seul local_path [0] est utilisé, mais l'API sera définie en vérifiant local_path [1] et local_path [2] dans l'ordre. Le reste est de simples opérations sur les fichiers. La raison pour laquelle vous vérifiez d'abord la taille du fichier est que si vous chargez un fichier vide dans json.load (), une erreur se produira, donc si le fichier est vide, les données reçues seront écrites dans le fichier telles quelles. (Les opérations sur les fichiers ici sont redondantes et confuses.)
La partie qui crée la réponse finale est la même que OPTIONS et la gestion des erreurs n'est pas prise en compte.
else:
print( "no" )
print( self.path )
return
C'est à ce moment qu'une URL inattendue arrive. Normalement, il devrait renvoyer une erreur 404, mais comme ce n'est pas un service public, il est clairement omis.
do_GET
do_GET
def do_GET(self):
print( "get" )
local_path = self.path.strip("/").split("/")
#Traitement des réponses
if( local_path[0] == "dat" ):
print( "dat" )
if(os.path.getsize('./dat.json')):
with open('./dat.json', 'r') as json_open:
json_load = json.load(json_open)
else:
json_load = {}
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
body_json = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
self.wfile.write(body_json.encode("utf-8"))
return
else:
print( "no" )
print( self.path )
return
La partie de base est la même que POST. Il élimine l'acquisition de données JSON à partir de la demande, lit le fichier et place ces données dans la réponse.
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
body_json = json.dumps(json_load, sort_keys=False, indent=4, ensure_ascii=False)
self.wfile.write(body_json.encode("utf-8"))
La différence avec POST est que Content-type est ajouté à l'en-tête et que les données sont écrites dans la partie du corps.
do_DELETE
do_DELETE
def do_DELETE(self):
print( "delete" )
local_path = self.path.strip("/").split("/")
if( local_path[0] == "dat" ):
print( "dat" )
with open('./dat.json', 'w') as file_open:
pass
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, DELETE')
self.send_header('Access-Control-Allow-Headers', '*')
self.end_headers()
return
else:
print( "no" )
print( self.path )
return
DELETE ouvre simplement le fichier cible avec l'attribut w et le ferme sans rien faire pour en faire un fichier vide.
rest_server
rest_server
def rest_server(port):
httpd_rest = http.server.ThreadingHTTPServer(("", port), RestHandler)
httpd_rest.serve_forever()
C'est une fonction qui démarre simplement le serveur sur le port spécifié par l'argument.
main
main
def main():
#Démarrage du serveur
port_rest = 3333
try:
t1 = threading.Thread(target=rest_server, args=(port_rest,), daemon = True)
t1.start()
while True: time.sleep(1)
except (KeyboardInterrupt, SystemExit):
print("exit")
sys.exit()
J'essaye de démarrer le serveur dans un thread séparé. En outre, le programme se termine lorsqu'il reçoit une interruption de fin (Ctrl + C) du clavier.
Lorsque vous démarrez le script, le serveur démarre sur le port 3333, essayez donc d'exécuter la commande suivante.
curl -X POST -H 'Content-Type:application/json' -d '{"key":"val"}' localhost:3333/dat
curl -X GET localhost:3333/dat
curl -X DELETE localhost:3333/dat
La commande est définie sur localhost car elle est exécutée à partir de la même machine que le serveur. Si vous utilisez une autre machine, essayez d'utiliser l'adresse IP de la machine qui sera le serveur.
J'ai pu construire un serveur REST pour le moment. Si vous souhaitez ajouter une API, vous pouvez de plus en plus imbriquer l'analyse de chemin. De plus, comme vous pouvez facilement appeler une autre commande, vous pouvez l'étendre afin qu'elle puisse également être utilisée pour la gestion du système.
Essayez-le.
Recommended Posts