'Access-Control-Allow-Origin' error on websocket connection - java

I'm trying to connect to my websocket from a different domain.
The server is on localhost:8098 and the client is on localhost:8080.
Everytime i try to connect i get a 'Access-Control-Allow-Origin' error, i also added the .setAllowedOrigins("*").
Not sure what's missing.
Server
#Configuration
#EnableWebSocketMessageBroker
public class webSocketObjects implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws/Object").setAllowedOrigins("*").withSockJS();
}
Client
<script>
let stompClient=null;
import Stomp from 'stompjs';
import SockJS from 'sockjs-client'
export default {
name: "modal",
props: ['node'],
data() {
return{
bacnetObject: '',
status: "disconnected"
}
},
mounted() {
this.bacnetObject = this.node;
},
methods: {
connect: function(){
const socket = new SockJS('http://localhost:8098/ws/Object');
stompClient = Stomp.over(socket);
stompClient.connect({
}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/user', console.log(String.body))
})
},
disconnect: function () {
stompClient.disconnect();
}
}
}
</script>
Error I am getting:
Access to XMLHttpRequest at 'http://localhost:8098/ws/Object/info?t=1571728150435' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

If you're using credentials, * would not work according to the documentation at MDN. Try to specify the host instead.
For requests without credentials, the literal value "*" can be specified, as a wildcard; the value tells browsers to allow requesting code from any origin to access the resource. Attempting to use the wildcard with credentials will result in an error.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
On the other hand, sometimes depending on your case, you may need to take care of these headers
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: header1, header2 ...
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests

Related

POST an appointment/reservation - CORS Policy problems

I try to post a dictionary with data for a reservation. But chrome logs this error:Access to XMLHttpRequest at 'http://localhost:8080/reservations' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
This is strange since I can post images, videos, html content because I put a #CrossOrigin annotation above my controllers. But with this particular post request it doesn’t seem to work.
rest controller:
#CrossOrigin(origins="http://localhost:4200",
maxAge=2000,allowedHeaders="header1,header2",
exposedHeaders="header1",allowCredentials= "false")
#RestController
public class ReservationsController {
private ReservationDao dao;
#Autowired
public ReservationsController(ReservationDao dao) {
this.dao = dao;
}
#PostMapping("/reservations")
public Map<String, String> bookReservation(#RequestBody Map<String, String> reservation) {
System.out.println(reservation);
return null;
}
}
angular api bookReservation method:
bookReservation(data) {
console.log(data);
const result = this.http.post(this.apiUrl + 'reservations', data).subscribe(
(val) => {
console.log('POST call succesful value returned in body',
val);
},
response => {
console.log('POST call in error', response);
},
() => {
console.log('The POST observable is now completed');
});
console.log(result);
}
If you set allowedHeaders only you will allow this params and if it receive other params it never send cross origing headers and chrome will throw error.
You should remove allowedHeaders, exposedHeaders and allowCredentials if you don't need them.

CORS error occurs when establishing a restAPI in springboot

trying to connect my RestAPI(SpringBoot) to angular but there's this cors error which does not allow the connection to happen.
the error in the front end side is
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/hello-world-bean/path-var/root. (Reason: CORS preflight channel did not succeed)."
And one more thing i am using the SpringBootSecurity Service by adding a username and password in application.properties file.
I tried to use Filter, WebMvcConfigurer, WebSecurityConfigurerAdapter but i am not in luck.
executeHelloWorldBean(){
return this.http.get<HelloWorldBeans>("http://localhost:8080/hello-world-bean/");
}
executeHelloWorldBeanWithParameter(name){
let basicAuthString = this.createBasicAuthenticationHeader();
let headers = new HttpHeaders({
Authorizaton : basicAuthString
})
return this.http.get<HelloWorldBeans>(`http://localhost:8080/hello-world-bean/path-var/${name}`,
{headers})
}
createBasicAuthenticationHeader(){
let username='root'
let password ='password'
let basicAuthString = 'Basic ' + window.btoa(username + ':' + password)
return basicAuthString}}
#Configuration
public class SpringSecurityBasicAuth implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(
"http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD")
.allowCredentials(true)
;
}
}
I just want my RestApi to be connected to my FrontEnd

No 'Access-Control-Allow-Origin' header present in request

I have read a lot of topic about this, and it still doesn't work, i'm loosing my mind.
I have an Angular6 App, with a Spring Api and i keep having this error when i call it :
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And yet i feel i did everything :
Here is my call to the api in Angular App:
getGamesFromServer() {
const httpOptions = {
headers: new HttpHeaders({
'Access-Control-Allow-Origin':'*'
})
};
this.httpClient
.get<any[]>('http://localhost:8080/api/rest/v1/game/progress', httpOptions)
.subscribe(
(response) => {
console.log(response);
this.games = response;
console.log(this.games);
this.emitGameSubject();
},
(error) => {
console.log('Erreur ! : ' + error);
}
);
}
Here is the java method called :
#RequestMapping(method = GET, value = "/progress")
#ResponseBody
public Response findAllAndProgress() {
return Response.status(Response.Status.OK)
.entity(gameService.findAllAndProgress())
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.build();
}
I have also started chrome with --disable-web-security option activated, and i also downloaded a chrome extension to allow CORS request but it was no use
I'm assuming it's because the Angular app is running in dev mode and is being served from a different port than the Spring webapp. You can either solve this with a proxy.conf.json file that you specify to the app startup (ng serve --proxy-config proxy.conf.json) or as a quick and dirty (but less production ready) solution you can add #CrossOrigin(origins = "*") to your Spring controllers.
The reason that the following code doesn't work:
#RequestMapping(method = GET, value = "/progress")
#ResponseBody
public Response findAllAndProgress() {
return Response.status(Response.Status.OK)
.entity(gameService.findAllAndProgress())
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.build();
}
is because that method never actually gets executed to add the header. Cross-origin requests initiate a preflight request (HTTP OPTION) before issuing the actual request (HTTP GET in your case). It is that preflight request that is failing. This is why adding the annotation to the controller will address the issue.
Create proxy.conf.json file in root directory with next content:
{
"/api/*": {
"target": "http://localhost:8080",
"secure": false
}
}
And in package.json file you must change start script from ng serve to ng serve --proxy-config proxy.conf.json
More details about proxy-config: Link
On java add following this line on your api
#CrossOrigin(origins = "http://localhost:4200")
You can also proxy your request from Angular side. Angular provide you inbuilt server that can proxy request. Following following steps:
Add proxy.config.json file on root directory of your project.
Add following code in proxy.config.json file
{
"/api/": {
"target": {
"host": "localhost",
"protocol": "http:",
"port": 8080
},
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
}
In package.json find start under scripts and replace with following:
ng serve --proxy-config proxy.config.json
Edit your angular code with following code:
this.httpClient
.get('/api/rest/v1/game/progress', httpOptions)
.subscribe(
(response) => {
console.log(response);
this.games = response;
console.log(this.games);
this.emitGameSubject();
},
(error) => {
console.log('Erreur ! : ' + error);
}
);

Send Notification to specific user in spring boot websocket

I want to send notification to specific client.
e.g username user
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends
AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
}
Controller
#GetMapping("/notify")
public String getNotification(Principal principal) {
String username = "user";
notifications.increment();
logger.info("counter" + notifications.getCount() + "" + principal.getName());
// logger.info("usersend:"+sha.getUser().getName()) ; //user
template.convertAndSendToUser(principal.getName(), "queue/notification", notifications);
return "Notifications successfully sent to Angular !";
}
Client-Side
Angular Service
connect() {
let socket = new SockJs(`api/socket`);
let stompClient = Stomp.over(socket);
return stompClient;
}
Angular Component
let stompClient = this.webSocketService.connect();
stompClient.connect({}, frame => {
stompClient.subscribe('/user/queue/notification', notifications => {
console.log('test'+notifications)
this.notifications = JSON.parse(notifications.body).count;
}) });
I am have searched many other questions and tried but none of them worked for me
e.g here answered by Thanh Nguyen Van and here
Console
Opening Web Socket...
stomp.js:134 Web Socket Opened...
stomp.js:134 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
stomp.js:134 <<< CONNECTED
version:1.1
heart-beat:0,0
stomp.js:134 connected to server undefined
reminder.component.ts:18 test callsed
stomp.js:134 >>> SUBSCRIBE
id:sub-0
destination:/user/queue/notification
thanks in advance .
The answer of gerrytan to Sending message to specific user on Spring Websocket mentions a web socket configuration change, to register the /user prefix. In your case I guess it means to replace
registry.enableSimpleBroker("/topic", "/queue");
with
registry.enableSimpleBroker("/topic", "/queue", "/user");
He also says that in controller you don't need the /user prefix because it is added automatically. So you could try this:
template.convertAndSendToUser(principal.getName(), "/queue/notification", notifications);
and this:
template.convertAndSendToUser(principal.getName(), "/user/queue/notification", notifications);
On the client side you need to provide the username that you used to connect to server. You might insert it directly:
stompClient.subscribe('/user/naila/queue/notification', ...)
or get it from a header. But Markus says at How to send websocket message to concrete user? that even here you don't need the username, so it might work like this:
stompClient.subscribe('/user/queue/notification', ...)
Seems you are missing a slash in your destination:
template.convertAndSendToUser(principal.getName(), "/queue/notification", notifications);

Http Server (Java on Vertx) not getting POST parameter

I am sending a ajax request from a client such as:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$(document).ready(function() {
$.ajax({
url: "http://192.168.1.74:8888",
type: "POST",
data: ({username: 'Bobby'})
});
})
</script>
</head>
<body>
</body>
</html>
My Http Server is written in Java utilizing vertx is like so:
public class Main extends AbstractVerticle {
#Override
public void start() throws Exception {
vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest request) {
System.out.println(request.getParam("username"));
}
}).listen(8888);
}
}
Every time I run the client, the server writes to console so the request is sent, but the server says the value is null. What am I doing wrong? How do I read the POST parameter being sent from the client?
UPDATE:
I found the problem, but no solution. If I change the ajax to GET from POST then it will appear. How do I make it so it works for POST and not for GET? SO the opposite of what is occurring now?
Cheers
I encountered the problem while working on my project. I was using Dojo on the client side. I manged to solve this by making adjustments both on the client side and the server side.
Client:
var json = JSON.stringify({
"username": "Bobby"
});
request.post("yoururl", {
data: json,
headers: {
"Content-Type": "application/javascript"
}
});
On the server side, apparently, what was required was calling the method BodyHandler.create() before handling the code.
router.route(HttpMethod.POST, "yoururl").handler(BodyHandler.create());
router.route(HttpMethod.POST, "yoururl").handler(routingContext ->
{
String sectionType = routingContext.request().getParam("sectionId");
JsonObject j = routingContext.getBodyAsJson();
});
I hope this would solved your problem.
When doing a POST request the data is in the body.
On the server side you need to register a body handler for your router in order to be able to easily get the body from the request. You can do that like this:
final Router router = Router.router(vertex);
// Adding a BodyHandler for routes
router.route().handler(BodyHandler.create());
router.post("/your/endpoint").handler(routingContext -> {
System.out.println(routingContext.getBodyAsString());
});
Another option is to add another callback handler like this:
final Router router = Router.router(vertex);
router.post("/your/endpoint").handler(routingContext -> {
routingContext.request().bodyHandler(body -> {
System.out.println(body.toString());
});
});
data: {"username": 'Bobby'} will fix your issue, and remove the () also you can try to change you ajax request in jquery as follow
var datavar = {username:"someusername"}; //Array
$.ajax({
url : "AJAX_POST_URL",
type: "POST",
data : datavar,
success: function(data, textStatus, jqXHR)
{
alert("success") ;
},
error: function (jqXHR, textStatus, errorThrown)
{
alert("fail") ;
}
});

Categories

Resources