简体   繁体   中英

Program throws 'Access-Control-Allow-Origin' header in JavaScript? Works in Postman, not through browser

Solved

I have been working on this program since 07:00. This has been driving me crazy. I have written multiple full stack web apps and have not had this problem.

Basically I have a form in html that allows a user to input data. Whenever the submit button is clicked, it sends that data to a collection in mongoDB. I have tested this in postman and it works. However, when I run the program through a webbrowser, I get this error:

XMLHttpRequest cannot load http://localhost:8080/articles/addArticle . No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 404.

I tried installing CORS and configuring the endpoint

I tried going into the javascript file and changing the

This is my JavaScript file

alert('JS is linked to page!');

function Article(id = 1, title = "", authors="", content = "", genre = "", date = 1497484623) {
    console.log("JavaScript file loaded successfully");
    var self = this;
    self.Id = id;
    self.Title = title;
    self.Authors = authors;
    self.Content = content;
    self.Genre = genre;
    self.Date = date;
    self.Save = function() {
        var settings = {
            url: 'http://localhost:8080/articles/addArticle',
            method: 'POST',
            dataType: "json",
              beforeSend: function (xhr) {
                xhr.setRequestHeader("Accept", "application/json");
            }
        };
        var myData = {
            "Id" : self.Id,
            "Title": self.Title,
            "Authors": self.Authors,
            "Content": self.Content,
            "Genre": self.Genre,
            "Date": self.Date
        };
        settings.data = myData;

        $.ajax(settings).done(function(article) {
         var myArticle = new Article(article.Id, article.Title, article.Authors,
                article.Content, article.Genre, article.Date);
        });
    };
}



function addArticle(Article) {
    alert('addArticle Activated');
    var settings = {
        url: 'http://localhost:8080/articles/addArticle',
        method: 'POST',
        dataType: "json",
          beforeSend: function (xhr) {
                xhr.setRequestHeader("Accept", "application/json");
            }
    };
    var myData = {      
        "Title": Article.Title,     
        "Authors" : Article.Authors,
        "Content": Article.Content,
        "Genre" : Article.Genre,
        "Date": Article.Date 
    };
    settings.data = myData;

    $.ajax(settings).done(function(Article) {
        var myArticle = new Article(article.Id, article.Title, article.Authors, article.Content,
            article.Genre, article.Date);
        console.log("Article Created");
    });
}

$(document).ready(function() {


    $(document).on("submit", "#add-article", function(e) {
        e.preventDefault();
            alert('submit Activated');
        var title, authors, genre, content;
        title = $("#Title").val();
        director = $("#Authors").val();
        rating = $("#Genre").val();
        notes = $("#Content").val();
        var myArticle = new Article(0, title, authors, genre, content, 1497484623);
        alert(myArticle.Title);
        addArticle(myArticle);
        $("#add-article")[0].reset();
        $("#title").focus();

    });

});

/*function CreateSuccessRow(Article) {
    var successDataRow = `<tr id="Article-${Article.Id}"><td>${Article.Title}</td>
                <td>${Article.Authors}</td>
                <td>${Article.Genre}</td>

Due to popular demand, this is the server-side code:

package com.stereoscopics.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.stereoscopics.app.models.Article;
import com.stereoscopics.app.repo.ArticleRepo;

@RestController
@RequestMapping("/articles")
public class ArticleController {

private ArticleRepo articleRepo;

@Autowired
public ArticleController(ArticleRepo articleRepo) {
    this.articleRepo = articleRepo;
}

@RequestMapping(value = "/findall", method = RequestMethod.GET)
@ResponseBody
public List<Article> findall() {
    return articleRepo.findAll();
}

@RequestMapping(value = "/addArticle", method = RequestMethod.POST)
@ResponseBody
public Article addArticle(@RequestBody Article newArticle) {
    articleRepo.save(newArticle);
    return newArticle;
}

}

I have no idea how to fix this. Please help.

UPDATE

This still isn't working. I've updated the code as per some suggestions and I'm either doing it wrong or it's incorrect. The changes are shown below:

  @RestController
  @RequestMapping("/articles")
  public class ArticleController {

private ArticleRepo articleRepo;

@Autowired
public ArticleController(ArticleRepo articleRepo) {
    this.articleRepo = articleRepo;
}

public void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
    response.addHeader("Access-Control-Allow-Origin", "*");
}

@RequestMapping(value = "/findall", method = RequestMethod.GET)
@ResponseBody
public List<Article> findall() {
    return articleRepo.findAll();
}

@RequestMapping(value = "/addArticle", method = RequestMethod.POST)
@ResponseBody
public Article addArticle(@RequestBody Article newArticle, final 
HttpServletResponse response) {
    response.addHeader("Access-Control-Allow-Origin", "*");
    articleRepo.save(newArticle);
    return newArticle;
  }
}

THIS IS NOT SOLVED YET

Basically what it says is that your service at http://localhost:8080/articles/addArticle . should add a header 'Access-Control-Allow-Origin' that the browser can read.

I ran to similar scenario when I was making a REST API, but instead of installing cors (which its version conflicts with our production server build), I just added that header when sending out responses to the request client.

response.AddHeader("Access-Control-Allow-Origin", "*");

If you are using asp.net, then you can either put that code in the Global.asax under:

protected void Application_BeginRequest(Object sender, EventArgs e) { 
    var context = HttpContext.Current;
    var response = context.Response; 
    response.AddHeader("Access-Control-Allow-Origin", "*"); 
}

If you are using java/servlet/jsp then it's quite similar as you already have access to HttpServletResponse response so in your code body, just do:

public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
    response.addHeader("Access-Control-Allow-Origin", "*");

    //other codes and stuff here...
} 

from your code on the other hand which uses spring, you could do something like:

@RequestMapping(value = "/addArticle", method = RequestMethod.POST)
@ResponseBody
public Article addArticle(@RequestBody Article newArticle, final HttpServletResponse response) {
    response.addHeader("Access-Control-Allow-Origin", "*");
    articleRepo.save(newArticle);
    return newArticle;
}

You can not solve cors as javascript end, I mean to say the problem is with your server code.

Cors is a security feature implemented by browser, let me tell you how it works.

when you query server, at first it hits with option method, at this time server sends allowed origins list, it can be one or multiple. now if your local domain or any domain is not present in that list then browser does not make the actual request.

To fix this you will have to configure cors filter on your server you can do it like

package com.package.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


 @Component
 public class SimpleCORSFilter extends GenericFilterBean {

/**
 * The Logger for this class.
 */
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void doFilter(ServletRequest req, ServletResponse resp,
                     FilterChain chain) throws IOException, ServletException {
    logger.info("> doFilter");

    HttpServletResponse response = (HttpServletResponse) resp;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
    //response.setHeader("Access-Control-Allow-Credentials", "true");
    chain.doFilter(req, resp);

    logger.info("< doFilter");
}

now if it's still not working then you will have to debug it line by line at server what's code, and at browser end you can test if option method has list of allowed origins or not.

I accidentally marked this as solved, when it clearly is not.

By including the port number in the Javascript url, the server threw an error because it mistook the request as originating from somewhere it wasn't supposed to come from. When I remove the port number, it doesn't know which port to hit. It should be hitting 8080 by default, but I'm getting another error.

To date, nobody has solved this problem. I've built apps without having this come up before and everyone I've asked at work seems to think I should just use spring forms. I'd ideally like to actually solve the problem instead of just finding work arounds.

Deal your CORS problem that you need to set the crossDomain first.

$.ajax({
  crossDomain:true
})

Next, you gonna to set the xhrFields in withCredentials .

$.ajax({
  crossDomain:true,
  xhrFields: {
    withCredentials: true
  }
})

In you Code , it's look like following this setting config.

let settings = {
    url: 'http://localhost:8080/articles/addArticle',
    method: 'POST',
    crossDomain:true,
    xhrFields: {
      withCredentials: true
    }
    dataType: "json",
      beforeSend: function (xhr) {
        xhr.setRequestHeader("Accept", "application/json");
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM