Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Access-Control-Allow-Origin' error even after following 2 approaches

I am trying to build an angular app to access data from MarkLogic database. I am using MarkLogic rest API to access the data. When I try to run the app, I get the following error.

XMLHttpRequest cannot load http://192.168.192.75:9550/v1/keyvalue?element=fieldId&value=1005&format=json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

I have read lot of answers related to this issue on stackoverflow but couldn't get anything working. Here is what I've tried till now.

1) Setting the response header using xdmp in qconsole
xdmp:add-response-header("Access-Control-Allow-Origin", "*");
xdmp:add-response-header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
xdmp:add-response-header("Access-Control-Allow-Headers", "x-requested-with, X-Auth-Token, Content-Type");
2) Tried to add headers by using REST [Extention][1]. Here is the example.sjs file which I wrote.
a) function get(context, params) {
  var results = [];
  context.outputTypes = [];
  for (var pname in params) {
    if (params.hasOwnProperty(pname)) {
      results.push({name: pname, value: params[pname]});
      context.outputTypes.push('application/json');
    }
  }
  context.outputStatus = [201, 'Created My New Resource'];
    context.outputHeaders = 
    {'Access-Control-Allow-Origin' : '*', 'Access-Control-Allow-Methods' : 'GET, OPTIONS, DELETE', 'Access-Control-Allow-Headers' : 'x-requested-with, X-Auth-Token, Content-Type'};
  return xdmp.arrayValues(results);
};
exports.GET = get;
b) curl --anyauth --user admin:admin -X PUT -i -H "Content-type: application/vnd.marklogic-javascript" --data-binary @./example.sjs http://192.168.192.75:9550/LATEST/config/resources/example

It doesn't seem to work, either ways. Can anyone please tell me if I am doing anything wrong? or If there are any other ways to get this working? Thanks in advance.

like image 601
DMA Avatar asked Oct 30 '22 01:10

DMA


2 Answers

This is probably due to Access-Control-Allow-Origin not allowed to be * when you are doing authentication. Or it could be due to pre-flight requests which are sent when the request is non-standard. Pre-flight are OPTIONS requests that are sent prior to the GET/POST/etc. to validate whether the actual call can be made. The way we have approached this is to front MarkLogic REST endpoints with Apache HTTP as a proxy. We have the following in a virtualhost configuration.

The ProxyPass is where the proxy to the ML REST endpoint is mapped. The other stuff sets the Access-Control-Allow-Origin header to the name of the requesting host. This is required as '*' is not allowed when authenticating. The RewriteCond and RewriteRule settings are used to respond to the pre-flight OPTIONS request, and just return a HTTP 200 status.

   <IfModule mod_headers.c>
    SetEnvIf Origin "^http(s)?://(.+\.)?(localhost|domain.com)(:[0-9]+)?$" origin_is=$0
    Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
    Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
    Header always set Access-Control-Max-Age "1000"
    Header always set Access-Control-Allow-Headers "X-Requested-With, content-type, Access-Control-Allow-Origin, Authorization, X-User-Id"
  </IfModule>

  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} OPTIONS
  RewriteRule ^(.*)$ $1 [R=200,L]

  # People DB REST Endpoint
  ProxyPass /people_dev http://10.239.12.223:8050

You can do the same with NginX or any other HTTP proxy.

like image 150
TJ Tang Avatar answered Nov 11 '22 07:11

TJ Tang


One alternative way I found is to define my own transform. This helps only for GET request method not for others. Here is what I created.

function customCors(context, params, content)
{
    xdmp.addResponseHeader('Access-Control-Allow-Origin' , '*');
    xdmp.addResponseHeader('Access-Control-Allow-Methods' , 'GET, PUT, POST, HEAD, OPTIONS, DELETE' );
    xdmp.addResponseHeader('Access-Control-Allow-Headers' , 'X-Requested-With, X-Auth-Token, Content-Type, Accept');
    return content;
};

exports.transform = customCors;

to use this we have to use a property called transform. Like this.

http://192.168.192.75:9550/v1/keyvalue?element=fieldId&value=1005&transform=customCors&format=json

Update: Reached out to MarkLogic, they said this can't be done in a 2-tier approach. We have to have a middle layer(3-tier) like java to add Origins/Methods etc.

like image 25
DMA Avatar answered Nov 11 '22 07:11

DMA