С моей программой SpringBoot связывается StompJS через сокет SockJS через WebSocket. Или, по крайней мере, я пытаюсь, чтобы это произошло. Раньше у меня была ошибка CORS; теперь клиент сообщает об ошибке 404. Я полагаю, что он не объявляет URL-адрес /info, который ожидает SockJS. Я думал, что сделал все, что нужно было сделать, чтобы SpringBoot сгенерировал это для меня.
Я понимаю, что /info является частью протокола SockJS. Чего я не понимаю, так это почему он не создается для меня.
Отчеты на вкладке Сеть Firefox 404
GET https://localhost:8081/bluecost/ws/info?t=1628490888709
{
"timestamp":"2021-08-09T06:34:50.126+0000",
"status":404,
"error":"Not Found",
"message":"No message available",
"path":"/bluecost/ws/info"
}
softlayer.component.ts (фрагмент)
onChooseBlueReportFile(files: FileList) {
console.log('@@@ onChooseBlueReportFile');
this.blueReportSelected = true;
this.blueReportFileName = files.item(0).name;
this.blueReportFile = files.item(0);
const pattern = /\d*[0-9]+[.]+\d{3}[0-9]$/;
if (this.blueReportFileName == null || this.blueReportFileName == 'No file selected') {
this.displayUploadBlueReportsError("No file selected.Please select one.");
} else {
this.errorBlueReport = false;
}
if (!this.errorBlueReport) {
this.showLoaderBlueReport = true;
var headers = {
};
var costFileClient = this.softlayerService.uploadCostFileAsync(this.blueReportFile);
console.log('Before webService connect');
var send_file = function(stompClient, input) {
let file = input.files[0];
read_file(file, (result => {
stompClient.send('/app/cost-file', { 'content-type': 'application/octet-stream' }, result)
}))
};
var read_file = function (file, result) {
const reader = new FileReader()
reader.onload = function(e) {
var arrayBuffer = reader.result;
}
reader.readAsArrayBuffer(file)
};
costFileClient.connect(headers,
/* Connect Callback */
function(frame) {
console.log('@@ Connected: '+frame);
send_file(costFileClient,files);
costFileClient.subscribe("/topic/softlayer-cost-file",
/* Subscribe Callback */
function(data) {
console.log('Incoming response from send: '+data);
}
);
},
/* Connect Error Callback*/
function(error) {
console.log('@@@ Error on connect: ' + error);
}
);
console.log('After webService connect');
}
}
softlayer.service.ts
uploadCostFileAsync(file: File) {
const reqOptions = {
headers: new HttpHeaders({
'X-Requested-With': 'XMLHttpRequest'
})
};
let formData = new FormData();
formData.append('file', file);
const socket = new SockJS('https://localhost:8081/bluecost/ws');
this.stompClient = Stomp.over(socket);
return this.stompClient;
}
WebSocketConfig.java
@Configuration
@EnableWebSocket
@Controller
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer
implements WebSocketConfigurer, WebSocketMessageBrokerConfigurer {
private static final Logger logger = LoggerFactory.getLogger(WebSocketConfig.class);
@Autowired
CostFileUploadWebSocketHandler costFileUploadWebSocketHandler;
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages.anyMessage().authenticated();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
logger.info("In registerWebSocketHandlers");
// registry.addHandler(new SocketTextHandler(), "/wst");
// registry.addHandler(costFileUploadWebSocketHandler, "/wsb/softlayer-cost-file");
registry
.addHandler(costFileUploadWebSocketHandler, "/bluecost/ws")
.setAllowedOrigins("*")
.withSockJS()
.setWebSocketEnabled(true)
.setHeartbeatTime(25000)
.setDisconnectDelay(5000);
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
logger.info("In registerStompEndpoints");
registry
.addEndpoint("/bluecost/ws")
.setAllowedOrigins("https://localhost:8448","https://localhost:8081") /* Removed * */
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
logger.info("In configureMessageBroker");
config.enableSimpleBroker("/topic/");
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(false);
configuration.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"));
configuration.setAllowedHeaders(Arrays.asList("Accept","Content-Type", "Access-Control-Allow-Headers", "Origin",
"x-requested-with", "Authorization"));
configuration.setExposedHeaders(Arrays.asList("X-Auth-Token","Authorization"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
WebSocketController.java
@Controller
public class WebSocketController {
private static final Logger logger = LoggerFactory.getLogger(WebSocketController.class);
@Autowired
private SimpMessageSendingOperations messagingTemplate;
@MessageMapping("/softlayer-cost-file")
@SendTo("/topic/softlayer-cost-file")
public String processMessageFromClient(@Payload String message) throws Exception {
ObjectMapper mapper = new ObjectMapper();
String name = mapper.readValue(message,Map.class).get("name").toString();
return name;
}
@MessageExceptionHandler
public String handleException(Throwable exception) {
messagingTemplate.convertAndSend("/errors", exception.getMessage());
return exception.getMessage();
}
}