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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With