go+iris+jwt+mysql+xorm+viper, un salon de discussion simple et pratique pour le projet iris, avec connexion, inscription, chat privé et chat de groupe.
Tout d’abord, jetez un œil à l’introduction du front-end sous ce document pour savoir comment le faire fonctionner (en raison d’une énergie limitée, l’interface utilisateur n’est pas particulièrement conviviale).
Accédez à l'adresse de démonstration. Si l'état de la petite icône ci-dessus est normal, vous pouvez y accéder. Elle peut entrer dans un état dormant et devoir attendre quelques secondes.
Le projet n'écrit actuellement que des adaptations liées à MySQL, mais en utilisant xorm, il n'est pas difficile de prendre en charge d'autres bases de données. Cela peut être fait, mais ce n'est pas nécessaire, Hahaha, si vous êtes trop paresseux pour l'exécuter vous-même, jetez-y un œil. à l'URL de démonstration Si vous êtes intéressé, personne n'a MySQL maintenant.
Je voulais à l'origine prendre en charge SQLite, afin qu'il n'y ait pas besoin de configurer les paramètres de la base de données, mais étant donné que la compilation de SQLite sous Windows nécessite la configuration de l'environnement gcc, ce qui est plus gênant, mais il n'y a pas d'effet de démarrage rapide, et ce n'est tout simplement pas complet , donc les autres bases de données ne sont pas prises en charge pour le moment (un jour, ajoutez-en plus lorsque vous en aurez le temps).
Le projet n'a donc besoin que de configurer les paramètres suivants
git clone https://github.com/JabinGP/demo-chatroom.git
cd demo-chatroom
// 复制config.toml.example 为 config.toml 并填写数据库信息,或者可选修改端口号
go run main.go
La valeur par défaut est le port 8888. Après le démarrage, accédez http://localhost:8888
J'ai utilisé React, mais je n'ai pas utilisé le framework UI. De nombreux petits détails ne sont pas bien exécutés. L'interface est conçue en fonction de la taille du téléphone mobile. Si vous ouvrez l'ordinateur, vous pouvez ouvrir f12. . Contentons-nous de cela. L'accent est mis sur cette dernière extrémité.
La boîte de discussion configure la fenêtre pour qu'elle défile automatiquement vers le bas, mais l'API est fournie par React et s'avère incompatible sur de nombreux navigateurs. Ce problème peut être résolu en utilisant le navigateur Chrome.
Après l'inscription, revenez manuellement et sélectionnez la connexion. Le nom rouge dans la boîte de message est destiné au discours public et le nom gris est destiné au chat privé. Vous pouvez spécifier le nom du destinataire dans la zone rouge. S'il n'est pas spécifié, la valeur par défaut est. discours public. Après spécification, seuls les utilisateurs correspondants peuvent voir les informations.
Votre nom d'utilisateur est affiché dans la case bleue. Cliquez pour vous déconnecter directement.
Le format de l'API est basé sur une conception reposante et la fonction de connexion est complétée à l'aide de jwt. De nombreuses interfaces nécessitent un statut de connexion, et JWT doit être transporté lors de la demande. Pour plus de détails, veuillez consulter la pratique jwt de golang iris. pratique pour les tests. La durée de validité de l'émission JWT n'est définie que pour 20 minutes. Elle doit être à nouveau expirée.
Le format de requête API est le même que l'interface générale. Get utilise Params, et Post, Put, Delete, etc. utilisent Json dans Body pour transmettre les paramètres.
Le format de retour est assez controversé. Je le recherche depuis un certain temps. Certaines personnes préconisent d'utiliser le code d'état http complet et d'ajouter du code au contenu du retour pour identifier les erreurs, comme ceci :
// 注册错误时
// http status 200
{
"code" : 40001 ,
"msg" : "注册用户名非法"
}
// 注册成功时
// http status 200
{
"code" : 200 ,
"msg" : "成功" ,
"data" : {
"username" : " JabinGP " ,
"id" : 3
}
}
D'autres préconisent d'utiliser des codes d'état http complets pour indiquer les erreurs :
// 注册错误时
// http status 400
{
"msg" : "注册用户名非法"
}
// 注册成功时
// http status 200
{
"username" : " JabinGP " ,
"id" : 3
}
En fait, les deux approches ci-dessus ont leurs propres avantages et inconvénients :
Sur la base de la situation ci-dessus, je combinerai les deux :
En cas de succès, renvoyez le code d'état http 200
// 注册成功时
// http status 200
{
"username" : " JabinGP " ,
"id" : 3
}
En cas d'échec, sélectionnez plusieurs codes d'état couramment utilisés pour exprimer l'erreur, 400 (erreur de demande), 500 (erreur interne du serveur), 404 (introuvable), 401 (échec d'authentification), classifiez grossièrement l'erreur, puis renvoyez Personnaliser un code, msg et détails dans les données pour représenter la cause détaillée de l'erreur :
// 注册失败
// http status 400
{
"code" : 6 ,
"msg" : "数据检验失败" ,
"detail" : "用户名已存在"
}
// 登录失效
// http status 401
{
"code" : 8 ,
"msg" : "未认证登录" ,
"detail" : " Token is expired "
}
Après cette combinaison, le rappel réussi est réussi et il n'est pas nécessaire d'écrire res.data.data. Le rappel d'erreur ne gère que les erreurs, qui peuvent être jugées par le code d'état http et peuvent être codées, envoyées et détaillées. .pour gérer les erreurs.
La liste des API est la suivante. Remplacez localhost par mike.jabingp.cn ou vous pouvez directement demander au backend de démonstration :
Fonction | Méthode de demande | adresse |
---|---|---|
Obtenir un jeton de connexion | POSTE | http://localhost:8888/v1/login |
Trouver des utilisateurs | OBTENIR | http://localhost:8888/v1/user |
registre | POSTE | http://localhost:8888/v1/user |
Les utilisateurs modifient eux-mêmes les informations | METTRE | http://localhost:8888/v1/user |
L'utilisateur envoie un message | POSTE | http://localhost:8888/v1/message |
L'utilisateur obtient des informations | OBTENIR | http://localhost:8888/v1/message |
L'utilisateur obtient des informations sur le jeton | OBTENIR | http://localhost:8888/v1/token/info |
Les paramètres détaillés de la requête peuvent être consultés dans la documentation postman-api de demo-chatroom.
Ou consultez le code source. Les paramètres de requête peuvent être visualisés dans model/reqo
et les paramètres de réponse peuvent être visualisés dans model/reso
AJAX n'est pas le meilleur choix car la fonction de chat est meilleure, mais on m'a demandé d'utiliser AJAX, je n'ai donc pas choisi cette dernière.
Le front-end du projet est relativement simple car il n’est utilisé que comme démo.
Mon anglais n'est pas très bon et les commentaires du code sont en anglais simplement parce que je suis trop paresseux pour changer de méthode de saisie.
C'est la première fois que j'utilise go pour développer un projet web, et c'est aussi la première fois que j'utilise React pour écrire le front-end Puisque le front-end ne prête pas beaucoup d'attention à la structure du projet (xjbx), je ne le ferai pas. Mettez le code source. Je compile le projet et le mets dans le dossier Assets pour plus de lisibilité. Il est très médiocre, mais il peut être démarré avec le backend. Il n'est pas nécessaire de démarrer le frontend séparément, ce qui est plus pratique pour voir le code source. effet. Si j'ai encore le temps, j'envisagerai d'écrire une version minimaliste en natif pour la référence de chacun.
C'est la première fois que j'utilise ORM pour faire fonctionner une base de données. Cela semble très difficile à utiliser. Je préfère écrire du SQL à la main. Il y a de nombreux effets souhaités et je ne trouve pas de solution après avoir lu les documents pendant longtemps. J'envisagerai d'utiliser SQLX pour le reconstruire plus tard.
Récemment, je me suis davantage intéressé à Go et j'ai reçu une tâche pour écrire un simple salon de discussion. J'ai découvert qu'il existe actuellement peu de pratiques de projet dans iris, seulement quelques exemples au niveau HelloWorld, j'ai donc décidé d'utiliser Go pour le faire. , puis ouvrez-le pour référence mutuelle. Bien sûr, la façon de concevoir la structure du projet est entièrement basée sur mon expérience limitée en développement. Veuillez donner votre avis précieux sur tout aspect déraisonnable.
Ce projet a les exigences suivantes
La fonction de connexion est cette fois implémentée en utilisant JWT
. Les avantages et les inconvénients de JWT
et Session
ne seront pas discutés en détail.
La base d'AJAX est un must pour tous les projets de séparation front-end et back-end, donc cette fonction ne sera pas trop discutée ici. L'accent n'est pas mis sur l'actualisation. Quelle est la difficulté ?
La logique de fonctionnement de l'utilisateur est d'envoyer des données dans la salle de discussion, puis les données sont envoyées. L'interface de discussion doit afficher les données envoyées par lui-même et mettre à jour les données envoyées par d'autres en temps réel.
Le front-end et le back-end communiquent via AJAX. Les données d'envoi du front-end et les données d'envoi du back-end peuvent être exprimées comme suit.
Quel est le problème ici ? Le problème est que le front-end ne peut lancer des requêtes que de manière active, et le back-end ne peut qu'accepter des requêtes. Cela signifie que les derniers messages ne peuvent jamais être envoyés activement du backend au frontend en temps réel. Les derniers messages ne peuvent d'abord être stockés que dans le backend, puis attendre que le frontend lance une requête avant que le backend puisse renvoyer des données.
Étant donné que le backend n'a pas la capacité de transmettre activement des messages au frontend, la solution permettant aux utilisateurs d'obtenir les dernières données est que le frontend règle une minuterie每隔一段比较短的时间就请求一次后台接口(轮询)
, de sorte que les données peuvent être continuellement mises à jour.
Le front-end a décidé d'utiliser AJAX pour interroger régulièrement l'interface d'arrière-plan afin d'obtenir les dernières données. Dans un souci de données en temps réel, l'intervalle d'interrogation sera小于1s
, cela entraînera un autre problème. Dans des requêtes aussi fréquentes, le backend ne doit pas transmettre toutes les données à chaque fois. L'un est l'efficacité de la transmission du réseau et le coût du trafic causés par la taille des données. Le jugement du front-end sur les nouvelles données signifie que le back-end doit renvoyer à chaque fois des données que le front-end n'a pas reçues. Le problème est le suivant : comment le back-end sait-il quelles informations le front-end a reçues ?
Cela nécessite l'utilisation de自增主键
du message. Le front-end n'a besoin que de transporter最后的消息的主键
reçu par le front-end à chaque fois qu'il fait une demande, car la clé primaire n'est pas une clé primaire. en répétant et en augmentant automatiquement, nous pouvons facilement trouver le rapport. Les données avec une grande clé primaire sont les données que le front-end n'a pas encore reçues.
langue
cadre
stockage de données
technologie
Grâce à l'utilisation du framework ORM de base de données Xorm, les tables suivantes sont automatiquement générées et sont accompagnées du champ
xxxxxx_at
Sur la base des exigences ci-dessus, deux tableaux, users
et messages
ont été conçus.
Champs clés
Structure des tables de base de données
Champ | Taper | Nul | Clé | Défaut | Supplémentaire |
---|---|---|---|---|---|
IDENTIFIANT | grosint(20) | NON | PRI | NUL | auto_increment |
nom d'utilisateur | varchar(255) | OUI | NUL | ||
mot de passe | varchar(255) | OUI | NUL | ||
genre | grosint(20) | OUI | NUL | ||
âge | grosint(20) | OUI | NUL | ||
intérêt | varchar(255) | OUI | NUL | ||
créé_à | dateheure | OUI | NUL | ||
mise à jour_at | dateheure | OUI | NUL | ||
supprimé_at | dateheure | OUI | NUL |
Champs clés
Structure des tables de base de données
Champ | Taper | Nul | Clé | Défaut | Supplémentaire |
---|---|---|---|---|---|
IDENTIFIANT | grosint(20) | NON | PRI | NUL | auto_increment |
expéditeur_id | grosint(20) | OUI | NUL | ||
id_récepteur | grosint(20) | OUI | NUL | ||
contenu | varchar(255) | OUI | NUL | ||
envoyer_heure | grosint(20) | OUI | NUL | ||
créé_à | dateheure | OUI | NUL | ||
mise à jour_at | dateheure | OUI | NUL | ||
supprimé_at | dateheure | OUI | NUL |
La structure suivante est basée sur votre expérience personnelle. S'il y a quelque chose d'inapproprié, veuillez nous faire part de vos précieux commentaires.
pojo
C'est facile à comprendre, c'est l'entité correspondant à la base de données, mais cela ne nécessite pas de correspondance biunivoque avec les champs de la base de données.
reqo (objet de requête), reso (objet de réponse)
Lorsque vous effectuez des requêtes via différentes interfaces, les paramètres qui peuvent être transportés et les données de réponse sont également différents, de sorte qu'une entité de requête et une entité de réponse correspondantes sont conçues pour chaque interface.
Ce qui suit est ma compréhension personnelle
Contrôleur
La responsabilité principale est d'accepter les paramètres de requête de la requête, de les convertir en reqo, d'effectuer une simple vérification des paramètres de requête (ma définition personnelle est une vérification qui n'a rien à voir avec la base de données, comme non nulle, non nulle), d'appeler la fonction de la couche Service pour obtenir le résultat pojo, et la conversion du résultat pojo est encapsulée et renvoyée dans reso.
Service
La responsabilité principale est d'encapsuler davantage l'interface de la couche Dao et de fournir une interface commune que le contrôleur peut appeler. Les données renvoyées peuvent être pojo. La vérification des données doit être effectuée dans le service, par exemple (ajout de nouveaux utilisateurs, vérification). le nom d'utilisateur est répété).
Dao
En gros, une méthode correspond ici directement à une instruction SQL sans aucune vérification. Les données reçues sont considérées comme fiables (elles ont été vérifiées par les paramètres des couches Contrôleur et Service), et les données renvoyées peuvent être des POJO.