Why is my controller config not allowing a cross-origin call? - javascript

I get this error message in my Browser Console, even though I think everything should be working. I´m just starting out with all of this, so I would be very gratefull if someone could help me out here.
Error: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/api/file/upload/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
This is my Post-Method in the Controller:
#CrossOrigin(origins = "http://localhost:4200", maxAge = 3600, allowCredentials="true")
#PostMapping("/upload/")
public ResponseEntity<Object> uploadBild(#RequestParam("file") MultipartFile file,
#AuthenticationPrincipal User user,
HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
System.out.println("File received Upload: " + file);
String[] allowedTypes = {"image/jpeg", "image/jpg", "image/png"};
if (!Arrays.asList(allowedTypes).contains(file.getContentType())) {
Map<String, String> responseBody = new HashMap<>();
responseBody.put("error", "Invalid file type. Only jpeg and png files are allowed");
return new ResponseEntity<>(responseBody, HttpStatus.BAD_REQUEST);
}
PictureDTO pictureDTO = new PictureDTO();
pictureDTO.setTitle(file.getOriginalFilename());
Picture picture = pictureService.save(pictureDTO, user);
if (uploadService.saveFile(file, picture.getId())){
Map<String, String> response1 = new HashMap<>();
response1.put("message", "File uploaded successfully");
return new ResponseEntity<>(response1, HttpStatus.OK);
}
else {
Map<String, String> response2 = new HashMap<>();
response2.put("message", "File upload failed");
return new ResponseEntity<>(response2, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
These are my application.properties:
spring.data.mongodb.uri=mongodb://user1:pass1#localhost:27017/?authSource=db1&replicaSet=rs1
spring.data.mongodb.database=db1
com.example.demo.accessTokenExpirationMinutes=5
com.example.demo.refreshTokenExpirationDays=30
accessTokenSecret=12345
refreshTokenSecret=54321
spring.web.cors.enabled=true
spring.web.cors.allow-origin=http://localhost:4200
spring.web.cors.allow-credentials=true
This is my WebSecurityConfiguration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(accessTokenEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(accessTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
And this is my frontend API Call:
uploadFile(file: File) {
const formData = new FormData();
formData.append('file', file);
this.http.post('http://localhost:8080/api/file/upload/', formData,{headers: {"Content-Type":"multipart/form-data"}}).subscribe(response => {
console.log(response);
// this.watermarkImage(file, "COPYRIGHT")
});
}
I hope this is enough information. Thank you very much! Best regards!

Related

RequestDispatcher.forward() not forwarding when servlet called via Ajax POST

I have a login page where I authenticate the user via firebase and send the request to a servlet. When I hit the submit button with correct authentications, the firebase authentication works, servlet get called but in browser I see see an error.
First of all, this is my javascript code
function toggleSignIn() {
if (firebase.auth().currentUser) {
alert('existing user');
firebase.auth().signOut();
} else {
var email = document.getElementById('email').value;
var password = document.getElementById('password').value;
if (email.length < 4) {
alert('Please enter an email address.');
return;
}
if (password.length < 4) {
alert('Please enter a password.');
return;
}
firebase.auth().signInWithEmailAndPassword(email, password).then(function (firebaseUser) {
var email = firebase.auth().currentUser.email;
const options = {
method: 'POST',
url: 'LoginValidator',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `email=${email}`
}
url = 'LoginValidator'
fetch(url, options)
.then(response = > response.json())
.then(data = > console.log(data))
.catch(e = > console.error(e))
}).catch(function (error) {
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
alert('Wrong password.');
} else {
alert(errorMessage);
}
console.log(error);
document.getElementById('quickstart-sign-in').disabled = false;
});
}
document.getElementById('quickstart-sign-in').disabled = true;
}
HTML
<div id="login-box" class="col-md-12">
<div class="form-group">
<input type="text" name="email" id="email" class="form-control login-input" placeholder="username">
</div>
<div class="form-group">
<input class="form-control login-input" type="password" placeholder="Password" id="password" name="password">
<i id="open" class="fa fa-eye fa-2x"></i>
<i id="closed" class="fa fa-eye-slash fa-2x"></i>
</div>
<div class="form-group">
<input type="submit" id="quickstart-sign-in" name="quickstart-sign-in"
class="form-control btn btn-info btn-md login-bt" value="Login" onclick="toggleSignIn()">
</div>
<div class="form-group text-center forgot">
Forgot username / password?
</div>
</div>
Below is my servlet
LoginValidator.java
public class LoginValidator extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String email = request.getParameter("email");
System.out.println("Printing email: "+email);
try {
System.out.println("inside try");
User user = new User();
UserRight userRight = new UserRight();
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateTypeDeserializer());
Gson gson = gsonBuilder.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BaseURLs.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
//Get user
RestEndPointsInterface endPoint = retrofit.create(RestEndPointsInterface.class);
Call<User> call = endPoint.getUserByEmail(email);
user = call.execute().body();
System.out.println(user.getName());
//Get user rights
Call<UserRight> userRightCall = endPoint.getUserRightByID(user.getUserRights().getIduserRight());
userRight = userRightCall.execute().body();
System.out.println(userRight.getUserRight());
if(userRight.getUserRight().equals("admin"))
{
response.getWriter().write("{url:LoadSellPendingApprovals}");
}
else
{
response.getWriter().write("{url:index.html}");
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
The LoginValidator calls LoadSellPendingApprovals, below is its code
public class LoadSellPendingApprovals extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
List<ProductSellAdvertisement> categoryList = new ArrayList<ProductSellAdvertisement>();
try {
System.out.println("INSIDE LoadSellPendingApprovals");
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Date.class, new DateTypeDeserializer());
Gson gson = gsonBuilder.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BaseURLs.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RestEndPointsInterface endPoint = retrofit.create(RestEndPointsInterface.class);
Call<List<ProductSellAdvertisement>> call = endPoint.getAllPendingApprovals();
categoryList = call.execute().body();
for (int i = 0; i < categoryList.size(); i++) {
System.out.println(categoryList.get(i).getProduct().getProductName());
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/jsp/product-sell-pending-approvals.jsp");
request.setAttribute("approvalList", categoryList);
requestDispatcher.forward(request, response);
}
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
This is the error I get
SyntaxError: Unexpected token < in JSON at position 0
at (index):71
The line being pointed in my javascript code is this - .then(response => response.json())
The expected behavior is this
User enter credentials
Authenticate the credentials with firebase javascript api
If credentials are correct send them to the LoginValidator servlet where it will further check user`s authenticity.
Then the LoginValidator send the request to LoadSellPendingApprovals where it will execute the following code
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/WEB-INF/jsp/product-sell-pending-approvals.jsp");
request.setAttribute("approvalList", categoryList);
requestDispatcher.forward(request, response);
In addition to the error I get, I never get forwarded to the JSP page as well. How can I fix this problem?
I am coming from java and mobile background, have no much clue on Javascript technology. Therefor appreciate detailed clear answers.
Your error indicates that the result "body" does not contain JSON but HTML:
Unexpected token < in JSON at position 0
JSON would look like this:
{ key: value }
HTML looks like this:
<html>....</html>
As the error states, the first < (position 0) is the "unexpected token". What ever is reading the body was expecting a {.
One reason for this might be that the request you are sending is redirected to a login page and therefore you get HTML instead of the expected JSON. Or you get an error page which you are trying to pass to your JSON parser.
Unfortunately, with this little information it is hard to tell. You should debug your code and check the response you are getting.

D3 v5 Post using fetch returning Unhandled promise rejection 405

I'm trying to use D3 fetch to post values to my servlet, following this link: https://beta.observablehq.com/#mbostock/posting-with-fetch.
Is anybody able to advise what is going wrong here? - thanks in advance.
My D3 Fetch statement is as follows:
d3.select('#myButton').on('click', function(){
d3.json("${pageContext.request.contextPath}/SomeServlet", {
body: JSON.stringify({"valuetosubmit": "test"}),
headers: {"content-type": "application/json"},
method: "POST",
mode: "cors"
})
});
Extract from my dummy servlet that isn't being reached below:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, String> options = new LinkedHashMap<>();
String searchno=request.getParameter("searchedPart");
System.out.println(searchno);
options.put("value1", "label1");
options.put("value2", "label2");
options.put("value3", "label3");
String data = new Gson().toJson(options);
System.out.println(data);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(data);
}
Which is throwing the following error: Unhandled Promise Rejection: Error: 405

Download a file from spring boot rest services from angular 5

I have spring boot service which provides csv file as response.
How do we call this service from angular 5 typescript.
download of a file should happen depends on some input parameters so I will have post call with user clicks the export button.
below is the rest code in controller.
#Controller
public class MyController {
#RequestMapping(value = "/downLoadDataQueryCsv", method = RequestMethod.GET)
public ResponseEntity<Object> downLoadDataQueryCsv(Model model) throws IOException {
FileWriter fileWriter = null;
try {
DataQueryRequestParams dataQueryRequestParams = new DataQueryRequestParams();
dataQueryRequestParams.setMbuCategory("UKY");
// Result table.
List<OrderIdFinalRank> rankList = // call api to get data.
// construct headers
List<String> csvHeaders = constructDataQueryHeaders();
StringBuilder fileContent = new StringBuilder(String.join(",", csvHeaders));
fileContent.append("\n");
// construct file content from response
for(OrderIdFinalRank finalRank : rankList) {
fileContent.append(StringUtils.join(constructDataQueryRow(finalRank), ",")).append("\n");
}
String fileName = new String("DataQueryTab.csv");
fileWriter = new FileWriter(fileName);
fileWriter.write(fileContent.toString());
fileWriter.flush();
File file = new File(fileName);
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getName()));
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
ResponseEntity<Object> responseEntity = ResponseEntity.ok().headers(headers).contentLength(file.length())
.contentType(MediaType.parseMediaType("application/txt")).body(resource);
return responseEntity;
} catch (Exception e) {
System.out.println("Exception: " +e);
return new ResponseEntity<>("Error occurred", HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
if(null != fileWriter) {
fileWriter.close();
}
}
}
}
Now I need to call this from UI when I click export button, what have written is below.
I have read file saver and added below code, but its not working. kindly help me.
#Injectable()
export class ApiService {
onExport(dataQueryRequestParams: any) {
const dataQueryURL = API_URL + '/downLoadDataQueryCsv';
const body = JSON.stringify(dataQueryRequestParams);
this._http.get(dataQueryURL).subscribe(res => {
saveAs(res, 'data.csv');
});
}
}
Note: When I ran rest URL from browser the file is downloaded, but the same needs to happen when I click export button.
Am new to UI technologies.
Thanks
I have fixed problem with below code.
export class ApiService {
onExport(requestParams: any): Observable<any> {
const dataQueryURL = API_URL + '/downLoadDataQueryCsv';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'Application/json; charset=UTF-8'
}),
responseType: 'text' as 'text'
};
const body = JSON.stringify(requestParams);
return this._http.post(dataQueryURL, body, httpOptions);
}
}
added below in caller Component class.
export class Component implements OnInit {
onExport() { this._apiService.onExport(this.dataQueryForm.value).subscribe(data => {
const blob1 = new Blob([data], { type: 'text/csv' });
FileSaver.saveAs(blob1, 'data.csv');
}) ;
}
}
Thank you all for your responses !

Why is this Cloud Function called more than once with an Android HTTP request trigger?

I have a function in an Android app which sends a POST request to an HTTP triggered Cloud Function. Whenever I click the button once to send the message, Firebase registers the event twice on the Firebase console. My application is built in such a way that the button to send a message disappears after the first click, so I'm not accidentally double clicking the button, and when I step through the debugger, the function to send the POST request is only called once. Can you guys help me? I don't know much about Firebase and can't find good documentation or other questions like this.
Here's the method which sends a message to my FCM cloud function:
public void sendPushToSingleInstance(final Context activity, final String message, final String myId, final String theirId) {
final String url = URL_TO_CLOUD_FUNCTION;
StringRequest myReq = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(activity, "Success", Toast.LENGTH_SHORT).show();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error.networkResponse != null)
Toast.makeText(activity, String.valueOf(error.networkResponse.statusCode), Toast.LENGTH_SHORT).show();
else
Toast.makeText(activity, "some error", Toast.LENGTH_SHORT).show();
}
}) {
#Override
public byte[] getBody() throws com.android.volley.AuthFailureError {
Map<String, String> rawParameters = new Hashtable<String, String>();
//not used
return new JSONObject(rawParameters).toString().getBytes();
};
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("from", myId);
headers.put("message", message);
headers.put("sendingTo", theirId);
return headers;
}
};
Volley.newRequestQueue(activity).add(myReq);
}
My JavaScript takes the HTTP request, cuts it up and send the message to a topic which contains the other user's id (I did mean to do this verses sending to a specific device).
Here's the JavaScript for my Cloud Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendMessage = functions.https.onRequest((request, response) => {
var topicId = request.get('sendingTo');
var color = request.get('color');
var from = request.get('from')
console.log('tried to push notification');
const payload = {
notification: {
title: from,
body: color,
sound: "default"
},
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
admin.messaging().sendToTopic(topicId, payload, options);
});
Finally, here are the logs:
firebase console logs
Which say that the function was called twice.
I've tried many links for answers such as the standard,
https://firebase.google.com/docs/functions/http-events
and many StackOverflow posts. I haven't seen anyone else with the same problem.
From #mohamadrabee, "this from the documentation 'Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system.' see firebase.google.com/docs/functions/http-events "
I added:
response.end();
after:
admin.messaging().sendToTopic(topicId, payload, options);
EDIT: After inserting this code, I still get the problem roughly 7% of the time. I had to change response.end(); to:
if (response.status(200)) {
response.status(200).end();
} else {
response.end();
}
I haven't had any problems since.

HttpRequestHandler : Sending a pdf file in response

I want server a pdf file instead of mp3 file please help
private HttpRequestHandler mRequestHandler = new HttpRequestHandler()
{
#Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context)
throws HttpException, IOException
{
try{
File file = new File("/mnt/sdcard/Music/song.mp3");
FileEntity body = new FileEntity(file, "audio/mpeg");
response.setHeader("Content-Type", "application/force-download");
response.setHeader("Content-Disposition","attachment; filename=song.mp3");
response.setEntity(body);
}catch(Exception e)
{
e.printStackTrace();
}
}
};
Change the content type to application/pdf
#Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context)
throws HttpException, IOException
{
try{
File file = new File("/my/path/file.pdf");
FileEntity body = new FileEntity(file, "application/pdf");
response.setHeader("Content-Type", "application/force-download");
response.setHeader("Content-Disposition","attachment; filename=file.pdf");
response.setEntity(body);
}catch(Exception e)
{
e.printStackTrace();
}
}
};
you can check mime types here

Categories

Resources