J'essaie de connecter mon client React.jsocks à mes sockets Web backend Spring Boot mais je n'arrive pas à les connecter, cela me donne des erreurs sur la console Chrome comme ceci :
Erreur de la console Chrome
Je n'ai aucune erreur dans ma partie Spring Boot, mais il y a quelques avertissements comme :
Console de démarrage Spring
Pourquoi je n'arrive pas à les connecter Ma partie React.js ressemble à ceci :
import background from'../Styles/Background.module.css' import formdesign from'../Styles/FormDesign.module.css' import Bounce from 'react-reveal/Bounce'; import cookies from 'js-cookie' import Menustyle from'../Styles/Menu.module.css' import {useLocation, useNavigate} from 'react-router-dom'; import { useState ,useEffect } from 'react'; import swal from 'sweetalert'; import Swal from 'sweetalert2' import { connect } from 'react-redux'; import { Oval } from 'react-loader-spinner'; import {GetWithAuth ,GetWithRefresh,beforeRegister,registerWithMail, beforeLogin} from '../Services/HttpServices'; import { isUserBlockExist } from '../Services/UserPrefs'; import SockJS from 'sockjs-client'; import { over } from 'stompjs'; let number = 1; const Login = (props)=>{ const navigate = useNavigate(); const location = useLocation(); const [isLoading, setIsLoading] = useState(true); const [allState,setAllState] = useState({ title:props.title, message:props.message, button:props.button, show:true }); const beforeLoad = async ()=>{ let sock = new SockJS(`${process.env.REACT_APP_ROOT_URL}/wss`); let stompClient = over(sock); stompClient.connect({},function(frame){ console.log("Connected : "+frame); //stompClient.subscribe("/user-connect/user",this.onPrivateMessage); }); try{ console.log(process.env.REACT_APP_ROOT_URL); let response = await GetWithAuth(`${process.env.REACT_APP_ROOT_URL}/auth/route`,"/homepage",props.jwtsession); if(response.route == "/"){ document.body.className = background.deneme; props.setJwtSession(""); //localStorage.removeItem("jwtsession"); } else{ document.body.className = Menustyle.deneme; } setIsLoading(false); navigate(response.route); } catch{ window.location.reload(); } } const handleClick = ()=>{ if(allState.show === false && number === 1){ setAllState({show:true,message:"Have Account ?",title:"Sign-Up"}); } else if(allState.show === false && number === 2){ setAllState({show:true,message:"Don't Have Account ?",title:"Login"}); } } const submit = async()=>{ if(document.getElementById("password").value.trim().length ==0){ swal({ title: "Password Field Is Required!", text: "Please Write Your Password", icon: "error", button: "Close This Alert", }); } else if(document.getElementById("username").value.trim().length ==0){ swal({ title: "Username Field Is Required!", text: "Please Write Your Username", icon: "error", button: "Close This Alert", }); } else if(document.getElementById("username").value.trim().length >=15&&allState.title!="Login"){ swal({ title: "Username Can Not More Than 15 Characters", text: "Please Try Another Username", icon: "error", button: "Close This Alert", }); } else if(document.getElementById("email")!=null && document.getElementById("email").value.trim().length ==0){ swal({ title: "E-Mail Field Is Required!", text: "Please Write Your E-Mail", icon: "error", button: "Close This Alert", }); } else if(allState.title === "Sign-Up"){ let postres = await beforeRegister(`${process.env.REACT_APP_ROOT_URL}/auth/beforeregister`,document.getElementById("username").value.trim(),document.getElementById("email").value,document.getElementById("password").value); if(postres.created == true){ Swal.fire({ html:`<h1>Please Write The Code We Sent To Your Email</h1> <input type="text" id="code" class="swal2-input" placeholder="CODE" style="width:50%;"> <button id="send" class="btn btn-success"> SEND </button><br/><br/> You Have <strong></strong> seconds.<br/><br/> `, timer:90000, icon: "success", allowOutsideClick:false, showCancelButton:true, didOpen: ()=>{ const content = Swal.getHtmlContainer() const $ = content.querySelector.bind(content) const send = $('#send'); const code = $('#code'); send.addEventListener("click",async()=>{ let postres2 = await registerWithMail(`${process.env.REACT_APP_ROOT_URL}/auth/registerwithmail`,code.value.trim().toLowerCase()); if(postres2.created == true){ props.setJwtSession(postres2.accessToken); //localStorage.setItem("jwtsession",postres2.accessToken); navigate('/homepage'); Swal.close(); } else if(postres2.created == false){ Swal.close(); swal({ title: postres2.error, text: "Please Check And Try Again", icon: "error", button: "Close This Alert", }); } }); Swal.showLoading(); setInterval(() => { Swal.getHtmlContainer().querySelector('strong') .textContent = (Swal.getTimerLeft() / 1000) .toFixed(0) }, 100) }}) } else{ swal({ title: postres.error, text: "Please Check And Try Again", icon: "error", button: "Close This Alert", }); } } else if(allState.title === "Login"){ let postres = await beforeLogin(`${process.env.REACT_APP_ROOT_URL}/auth/beforelogin`,document.getElementById("username").value.trim(),document.getElementById("password").value); if(postres.created == true){ Swal.fire({ html:`<h1>Please Write The Code We Sent To Your Email</h1> <input type="text" id="code" class="swal2-input" placeholder="CODE" style="width:90%; margin-left:0px;"> <button id="send" class="btn btn-success"> SEND </button> <button id="close" class="btn btn-secondary"> CLOSE </button><br/><br/> You Have <strong></strong> seconds.<br/><br/> `, timer:90000, icon: "success", allowOutsideClick:false, didOpen: ()=>{ const content = Swal.getHtmlContainer() const $ = content.querySelector.bind(content) const send = $('#send'); const code = $('#code'); send.addEventListener("click",async()=>{ let postres2 = await registerWithMail(`${process.env.REACT_APP_ROOT_URL}/auth/loginwithmail`,code.value.trim().toLowerCase()); if(postres2.created == true){ props.setJwtSession(postres.accessToken.toString()); console.log(postres.accessToken); navigate('/homepage'); Swal.close(); } else if(postres2.created == false){ Swal.close(); swal({ title: postres2.error, text: "Please Check And Try Again", icon: "error", button: "Close This Alert", }); } }); Swal.showLoading(); setInterval(() => { Swal.getHtmlContainer().querySelector('strong') .textContent = (Swal.getTimerLeft() / 1000) .toFixed(0) }, 100) }}) } else if(postres.created === false && postres.blocked == false){ swal({ title: postres.error, text: "Please Check And Try Again", icon: "error", button: "Close This Alert", }); console.log(postres); } else{ swal({ title: postres.error, text: "Please Check And Try Again", icon: "error", button: "Close This Alert", }); } } } useEffect(() =>{ beforeLoad(); },[]); useEffect( ()=>{ setTimeout(() => { if(allState.show === true && number === 1){ setAllState({show:false,message:"Have Account ?",title:"Sign-Up"}); number = 2; console.log(allState.message); } else if(allState.show === true && number === 2){ setAllState({show:false,message:"Don't Have Account ?",title:"Login"}); number = 1; } }, 300); },[allState]); if (isLoading) { return <div className={formdesign.loading}> <Oval width="100" height="100" color="black" ariaLabel='loading' /> </div>; } return( <div> <Bounce left opposite when={!allState.show}> <div className={allState.title =="Login" ? formdesign.formBack : formdesign.formBackSignUp}> <h1 className={formdesign.Title}>{allState.title}</h1> <input type="text" name = "username" placeholder={allState.title == 'Login' ? 'Username Or Email' : 'Username'} id='username'></input> {allState.title =="Sign-Up" && <input type="text" name = "email" placeholder="E-Mail" id='email'></input> } <input type="password" name = "password" placeholder="Password" id='password'></input> <input type="button" value={allState.title} onClick = {submit} ></input> <p>{allState.message} <span style={{color:"blue",cursor:"pointer"}} onClick = {handleClick}>Click Here</span></p> </div> </Bounce> </div> );} const mapStateToProps = (state)=>{ return{ jwtsession:state.jwtsession } } const mapDispatchToProps = (dispatch) =>{ return{ setJwtSession: (jwtsession) =>{ dispatch({'type':'SET_JWTSESSION',jwtsession})} } } export default connect(mapStateToProps,mapDispatchToProps) (Login);
Et mon cours de configuration Spring Boot :
package com.project.blog.websocket; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer { @Value("${blog.app.front}") private String url; @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/wss").setAllowedOrigins(url).setAllowedOriginPatterns("*").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.setApplicationDestinationPrefixes("/app"); registry.enableSimpleBroker("/user-connect"); registry.setUserDestinationPrefix("/user"); } }
De même pour le contrôleur de socket Web, j'ai écrit cette partie :
package com.project.blog.websocket; import com.project.blog.entities.User; import com.project.blog.repositories.UserRepository; import com.project.blog.responses.ErrorSuccessResponse; import lombok.RequiredArgsConstructor; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Controller; import java.time.LocalDateTime; import java.util.LinkedList; import java.util.List; @Controller @RequiredArgsConstructor public class WebSocketController { private final SimpMessagingTemplate simpMessagingTemplate; private final UserRepository userRepository; @MessageMapping("/message") private ErrorSuccessResponse receiveMessage(String user){ ErrorSuccessResponse errorSuccessResponse = new ErrorSuccessResponse(); errorSuccessResponse.setError("block oldu"); simpMessagingTemplate.convertAndSendToUser(user,"/private",errorSuccessResponse); return errorSuccessResponse; } @Scheduled(fixedDelay = 1000) private void checkBlocks(){ LocalDateTime now = LocalDateTime.now(); List<User> users = userRepository.findBlockedUsers(now); users.stream().forEach(user->{ receiveMessage(user.getUsername()); }); } }
J'ai essayé d'utiliser des chaussettes pour connecter mon frontend React.js et mon backend Spring Boot mais je ne peux pas
Mon process.env.REACT_APP_ROOT_URL est : http://localhost:1998 et @Value("${blog.app.front}") URL de chaîne privée ; la valeur de cette partie est : http://localhost:3000
Le problème peut être côté client ou côté serveur. La première étape consiste à pouvoir tester le serveur de manière isolée à l'aide d'un outil de test. Ce n'est pas simple car le code utilise le protocole STOMP sur SockJS.
Vous n'avez probablement pas besoin d'utiliser SockJS. Voir Utilisation de STOMP avec SockJS. La première étape consiste donc à supprimer l’utilisation de SockJS et à voir si cela fonctionne.
L'étape suivante consiste à annuler l'utilisation de STOMP. Une approche plus simple consiste simplement à utiliser des messages en texte brut. Si vous faites cela, vous pouvez tester le serveur vous-même à l'aide d'un outil de ligne de commande comme wscat ou d'un plugin de navigateur Chrome comme WebSocketKing. Une fois que le serveur fonctionne avec le harnais de test, vous pouvez utiliser le code client pour les tests.
J'ai rencontré un problème similaire et j'ai fini par développer mon propre protocole en utilisant des messages JSON, envoyés sous forme de messages texte WebSocket. Je peux tester le serveur de manière isolée à l'aide de WebSocket King. Faites défiler jusqu'à la fin de Brill Middleware pour voir un exemple utilisant WebSocket King.