No access-control-allow-origin header is present on the requested resource. jquery ajax

CORS는 동일한 도메인의 출처를 가진 자원만을 사용하게 끔 제한하는 보안상의 규약으로, 제한 주체는 브라우저입니다.

이를 해결하기 위한 근본적인 해결책은 자원을 제공하는 서버에게 있으며, 자원을 받는 질문자분의 위치에선 근본적인 해결은 불가능합니다.

예를 들어, API서버(A)와 질문자분의 서버(B)가 있다고 가정합니다.

A   =====>   B (CORS 제약)

B   =====>   B (정상)

대부분 외부 자원을 AJAX를 통해 받아오므로, $.ajax 시 많이 발생합니다.

많은 분들이 답변주신 Access Control Allow Origin 헤더 추가는 질문자분 쪽에서 해봐야 아무런 소용이 없습니다. 해당 헤더는 자원을 제공해주는 서버(예시에서의 A)에 추가해야 그 의미가 있는겁니다.

API서버(A)와 질문자분의 서버(B / 123.x.x.x)가 있다고 가정합니다.

API서버 측에서 Access Control Allow Origin의 값을 123.*.*.* 혹은 * 과 같이 지정하면 특정 IP 혹은 모든 IP에 대해 CORS에 상관없이 응답을 줄 수 있습니다.

A   =====> B 123.x.x.x (CORS 제약)

A (ACAO 123.*.*.*)  =====>   B 123.x.x.x (정상)

A (ACAO *)  =====>   B 123.x.x.x (정상)

즉, 위 해더는 질문자분이 나중에 API를 설계할때는 유용하게 쓰실 수 있겠으나, 받는 사람의 입장에선 아무 것도 할 수 없습니다.

CORS를 해결하는 방법에는 크게 3가지로 나뉩니다.

1. 수동적 해결

API 서버에 문의하는 방법입니다. API서버는 의도적이든 의도적이지 않든 API 응답의 접근을 제한합니다. CORS 같은 단순 규약에만 의존하지 않고, 자체적인 인증 단계를 거쳐 응답을 제공하기도 하죠.

수동적이지만 가장 쉬운 방법으로, 해당 API 제공 업체에 문의하여 API 응답을 받는 가이드라인이나 화이트 리스트에 본인 PC의 IP를 추가해달라고 요청할 수 있습니다.

가장 쉽고 편하지만, 유동 IP나 다수의 개발환경 등에서는 API 사용이 제한될 수 있기 때문에 여러모로 불편사항이 많습니다. 응답을 받는 것 이전에, 서비스 정책에 의해 응답을 제공해주지 않을 가능성도 많습니다.

2. 능동적 해결

JSP를 이용하고 계신걸 보니, 아마 Tomcat이나 JEUS를 연동하여 사용하고 계실 것 같은데, 본인만의 서버를 운용하고 다룰 수 있는 환경이라면, 조금 더 개발적인 관점으로 해결할 수 있습니다.

위에서 언급했듯이, CORS는 '브라우저'에서 제한하는 규약입니다. 즉, 브라우저 밖에서는 CORS가 힘을 못 씁니다. JAVA의 경우 브라우저 외부의 요소임으로, 필요한 URL을 질문자의 서버에 전달하여 JAVA 상에서 호출하고, 받은 응답을 자신의 서버에서 보여줌으로써 CORS를 극복하는 방법입니다.

즉, 일종의 API 미들서버를 만드는겁니다. 아래의 설명은 AJAX와 Servlet, HTTP 통신에 대한 기초적인 지식을 전제로 둡니다.

API서버(A)와 질문자분의 서버(B)가 있다고 가정합니다.

B (JS)   =====>   B (Servlet) : 본인의 서버로 API 호출에 필요한 요소를 전달합니다.

B (JAVA)   =====>   A : 본인의 서버에서 API를 호출합니다.

A   =====>   B (JAVA) : 브라우저가 아닌 서버(JAVA, Node.js etc.)에서 호출했으므로, 정상적으로 응답을 받을 수 있습니다.

B (Servlet)   =====>   B (JS) : 본인의 서버 자원을 호출했으므로, AJAX에 위배되지 않는다.

API가 단순히 URL만 호출하는 정도로 끝난다면, 쉽게 구현할 수 있습니다. URL을 호출하고 받는 응답을 그대로 받아 전달만 해주면 됩니다. 자바에서의 HTTP 통신은 Jsoup 라이브러리나 httpurlconnection 클래스를 참고해보세요.

위 방법을 통해 단순 개발이나 테스트로는 크게 문제되지 않지만, 특정 API의 결과를 불특정 다수에게 전달하는 것은 법적으로 문제가 발생할 수 있습니다.

3. 우회

크롬이나 엣지(크로뮴) 브라우저를 사용하고 계신다면, CORS를 무시하는 플러그인을 설치할 수 있습니다. 구글에 CORS 플러그인으로 검색하시면 여러개 나올겁니다.

또한 굳이 플러그인이 아니더라도, 크롬 바로가기에서 인자를 추가하여 CORS가 동작하지 않도록 옵션을 줄 수 있습니다.

아무쪼록 원하시는대로 잘 설계하시길 바랍니다.

I tried sending an AJAX request with jQuery to a SugarCRM REST endpoint, but it was blocked by Cross Origin Resource Sharing and returned HTTP 404 along with an error.

This is the AJAX request:

$.ajax({
        type: 'POST',
        url: 'https://example.sugarinstance.com/rest/v10/Cases/web/submit',
        data: jsonData,
        dataType: 'json',
        contentType: 'application/json',
        success: function(response) {
          console.log('SUCCESS')
          console.log(response)
        }
      })

And this is the error returned:

XMLHttpRequest cannot load https://example.sugarinstance.com/rest/v10/Cases/web/submit. Response to preflight request doesn't pass access control check: 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.

This is the endpoint I created just to test without authentication since it was not working at all:

<?php

class Web2CaseApi extends SugarApi
{
    public function registerApiRest()
    {
        return array(
            'Web2CaseEndpoint' => array(
                'reqType' => 'POST',
                'noLoginRequired' => true,
                'path' => array('Cases', 'web', 'submit'),
                'method' => 'newCase',
                'shortHelp' => 'Receives JSON data for a new Case record',
            ),
        );
    }
    public function newCase($api, $args)
    {
        return $args;
    }
}

This endpoint now appears in the API help, so it definitely exists.

How am I supposed to use AJAX to send data to SugarCRM if it is blocked?
Should the server be set to allow CORS by default?

I also tried these options in the jQuery AJAX request to no avail:

crossDomain: true,
headers: {
  'Access-Control-Allow-Origin': '*'
},