I'm trying to upload a custom image to my playlist on Spotify. Here's what happens: I make a request to the API to create a playlist using AJAX (this works) and then I want to upload a custom image to that newly made playlist also using AJAX. I've been following Spotify's guide on how to do that and believe that the headers, scopes, content type, etc... are all correct. Here is the code for uploading the image:
var playlistId = "newly_created_playlist_id_here";
var token = "access_token_here";
var url = c.toDataURL({ // encodes canvas image (declared as "c" in another file) to base64 jpeg format
format: 'jpeg', // file where "url" is declared is imported via the import / export method
quality: 0.8 // canvas is successfully encoded to jpeg base64
});
$.ajax({
url: "https://api.spotify.com/v1/playlists/" + playlistId +"/images",
type: 'PUT',
body: url,
headers: {
"Authorization": "Bearer " + token,
"Content-Type": "image/jpeg; charset=utf-8"
},
contentType: "image/jpeg",
error: function(err) {
console.log('Error: ' + err);
},
success: function(data) {
alert('Load was performed.');
}
});
I however receive a error 400 from Spotify as seen below:
PUT https://api.spotify.com/v1/playlists/my_playlist_id/images
400
Here is the HTTP header file contents:
Request URL: https://api.spotify.com/v1/playlists/my_playlist_id/images
Request Method: PUT
Status Code: 400
Remote Address: 35.186.224.25:443
Referrer Policy: no-referrer-when-downgrade
access-control-allow-credentials: true
access-control-allow-headers: Accept, App-Platform, Authorization, Content-Type, Origin, Retry-After, Spotify-App-Version, X-Cloud-Trace-Context
access-control-allow-methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
access-control-allow-origin: *
access-control-max-age: 604800
alt-svc: clear
cache-control: private, max-age=0
content-encoding: gzip
content-length: 86
content-type: application/json
date: Mon, 15 Jun 2020 09:53:52 GMT
server: envoy
status: 400
strict-transport-security: max-age=31536000
via: HTTP/2 edgeproxy, 1.1 google
x-content-type-options: nosniff
x-robots-tag: noindex, nofollow
:authority: api.spotify.com
:method: PUT
:path: /v1/playlists/my_playlist_id/images
:scheme: https
accept: application/json, text/javascript, */*; q=0.01
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
authorization: Bearer my_access_token
content-length: 0
content-type: image/jpeg
origin: http://127.0.0.1:5500
referer: http://127.0.0.1:5500/index.html
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Just to re-iterate what I've said earlier for clarification, The playlist is created with no errors and the image is encoded to base64 jpeg successfully too however when I try to upload the image to the new playlist, I receive the error 400. A new access token is also generated successfully.
I am using the following scopes when requesting access from the user:
ugc-image-upload
playlist-modify-public
playlist-modify-private
which are needed as described in the Spotify documentation.
I have no idea what I'm doing wrong here and I haven't found any other questions across the internet that answer my problem so any help is greatly appreciated!
This caused me a similar headache - it does work but the encoding of the image must be exact:
No newlines or spaces
Nothing like data:image/jpeg at the start of the string (see this answer)
While not relevant to the OP, the main issue in my case was my editor (VScode) adding a new line to the end of the text file with the encoded image when it was saved, which caused it to be rejected by the Spotify API.
For anyone else looking at this, I got it working by starting with a very basic base64 encoded image (see below) and then building up to the functionality I needed.
iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==
(A red dot, taken from this question.)
Related
I'm a newbie in Express so for this issue I've researched quite bit but I cannot get it right. So I need to pass an array like this ["1","2","3","4","5"] as a payload from Frontend, and in the Express I need to accept it and do stuff with it. So far, I can send it from Frontend and receive at Express but the content of what I receive does not look right. In the Express I receive:
POST / 200 3.239 ms - 97
{ '"1","2","3","4","5"': '' }
so I cannot do anything with this. I tried to send an object called params and receive that to do something with that, that didn't work either.
Frontend headers are like this
Request URL: http://localhost:5000/
Request Method: POST
Status Code: 200 OK
Remote Address: [::1]:5000
Referrer Policy: strict-origin-when-cross-origin
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 36
Content-Type: application/json; charset=utf-8
Date: Mon, 13 Dec 2021 23:06:58 GMT
ETag: W/"24-sEnfXlyl7goDTpCx3bZVIGauJsc"
Keep-Alive: timeout=5
X-Powered-By: Express
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 21
Content-Type: application/x-www-form-urlencoded
DNT: 1
Host: localhost:5000
Origin: http://localhost:3000
Referer: http://localhost:3000/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36
Express setup that relates to this is like
var express = require("express");
...
var app = express();
...
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post("/", (req, res) => {
res.json({ requestBody: req.body });
});
So how can I send as part of the body from frontend in ReactJS an array ["1","2","3","4","5"] then accept that as array in express and do stuff with it?
What you show as the request:
POST / 200 3.239 ms - 97
{ '"1","2","3","4","5"': '' }
And, the headers you show as:
Content-Type: application/x-www-form-urlencoded
Do not match. Your data is being sent as plain text. It's not application/json or application/x-www-form-urlencoded so you don't have a body-parser installed for it so Express doesn't know what to do with it. In fact, Express doesn't even read it, it just stays in the incoming stream.
You don't show the client-side code, but the client needs to make the content-type and the encoding of the body content you send with the POST actually match. Then, you need a body-parser for that content-type on the Express side of things.
Since this is meant to be an array of data, I would suggest using JSON and sending application/json encoded data. Then, your existing express.json() middleware will read and parse it for you and you can read the data in req.body.
If you want help fixing the client-side, then show us the client-side code that is sending this.
For example, if you were sending this from the client with fetch(), here's an example right from the MDN doc for fetch():
// Example POST method implementation:
async function postData(url = '', data = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('https://example.com/answer', { answer: 42 })
.then(data => {
console.log(data); // JSON data parsed by `data.json()` call
});
You should NOT send an object called params. Since its POST request, you should send the array as an property of the request body. Then it will be available in the req.body property in the Express app.
I am dealing with an external api. I want to post some data so i set a token in the headers to be able to access the api.
I am told that my test origin has been whitelisted http://127.0.0.1:8081/
However i get the following error.
Failed to load
https://external-api.com/api/transactions/ad2d7a69-f723-4798-9fa5-a95a76d65324/document:
Response to preflight request doesn't pass access control check: The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'.
async submitDocument(transationId, token, base64) {
const url = host + "/api/transactions/" + transationId + "/document"
const body = {
"image": base64,
}
let headers = new Headers();
headers.set('Content-type', 'application/json');
headers.set('token', token);
const request = {
method: 'POST',
body: JSON.stringify(body),
mode: 'cors',
headers: headers,
credentials: 'include'
}
const data = await fetch(url, request);
const response = await data.json();
return response;
}
This function call is being made browser side on the following page. http://127.0.0.1:8081/
Response from server
Request URL: https://externalapi.com/api/transactions/f400aaec-3fde-4458-a36e-fe03d550fc00/document
Request Method: OPTIONS
Status Code: 200
Remote Address: 54.194.37.150:443
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Headers: content-type, token
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 0
Connection: keep-alive
Content-Length: 0
Date: Fri, 22 Jun 2018 15:29:27 GMT
Server: nginx
Vary: Origin
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Access-Control-Request-Headers: content-type,token
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: externalapi.com
Origin: http://127.0.0.1:8081
Pragma: no-cache
Referer: http://127.0.0.1:8081/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
just read the error message carefully! Your domain must not be whitelistet with '*'.
It has to be 'http://127.0.0.1:8081'. You have to ask external-api.com to recheck it.
In your request you have credentials set in a token header and the Origin of your request is:
Origin: http://127.0.0.1:8081
The request in this case will proceed only if the server answers with:
Access-Control-Allow-Origin: http://127.0.0.1:8081
Otherwise the request is blocked by the browser
Check here for more details:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Examples_of_access_control_scenarios
In particular the section "Requests with credentials"
I am using the below Ajax call to connect with Spring security from crossdomain (PhoneGap). The response I got is 200 OK - it has the expected response in JSON format. But the error event is getting fired due to CORS. On the Spring side, I have added a CORS filter to allow any type of URL (Access-Control-Allow-Origin = ' * ').
$.ajax({
type:'POST',
url: CONTEXTPATH + '/j_spring_security_check',
data: formData,
dataType: 'text json',
cache: false,
crossdomain: false,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With' : 'XMLHttpRequest',
},
success: function(data) {
},
error: function(data) {
}
});
The response in the browser console is:
POST XHR http://192.168.0.20:8080/startupbay/j_spring_security_check [HTTP/1.1 200 OK 260ms] Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://192.168.0.20:8080/startupbay/j_spring_security_check. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
The request and response headers are:
RESPONSE HEADER:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, x-requested-with, Origin, Accept
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD
Access-Control-Allow-Origin:*
Access-Control-Max-Age:86400
Access-Control-Request-Headers:x-requested-with
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:0
Date: Thu, 23 Feb 2017 06:14:39 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
REQUEST HEADER:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.5
Access-Control-Request-Headers:x-requested-with
Access-Control-Request-Method:POST
Connection:keep-alive
Host:192.168.0.20:8080
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
origin:http://192.168.0.20:3000
In the Error section, I looked for the error mentioned in 'xhr'. The statusText:error, responseText:'', status:0.
Please help me in resolving this issue.
When I set the crossdomain:true, that time in the browser console I can see only the OPTIONS request, but not followed by the POST request.
Just to add, this issue is appearing only for the '/j_spring_security_check' URL. For another URL, the same type setup is working fine.
I'm developing an Azure MobileService / CordovaApp setup. The server runs locally and has the following setting to enable CORS:
<add name="Access-Control-Allow-Origin" value="*" />
The api can be called via browser using addresses like
http://localhost:59477/api/item/explore/A/B
The client script that's trying to depict this call is the following:
var client = new WindowsAzure.MobileServiceClient('http://localhost:59477/', 'http://localhost:59477/', '');
GetItems.addEventListener("click",
function ()
{
client.invokeApi("item/explore/A/B",
{
method: "get"
})
.done(
function (results)
{
alert(results.result.count);
},
function (error)
{
var xhr = error.request;
alert('Error - status code: ' + xhr.status + '; body: ' + xhr.responseText);
alert(error.message);
}
);
}
);
What I get is status 405 - Method not allowed, which I don't understand for two reasons:
The invoked Service Action is decorated with the [HttpGet] Attribute
The response headers seem to say GET is fine:
HTTP/1.1 405 Method Not Allowed
Allow: GET
Content-Length: 76
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RjpcQ29kZVxGb290UHJpbnRzXGZvb3RwcmludHMuU2VydmVyXEZvb3RwcmludHNTZXJ2aWNlXGFwaVxmb290cHJpbnRcZXhwbG9yZVw1MS4yNzcwMjJcNy4wNDA3ODM=?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Date: Sat, 15 Aug 2015 18:08:30 GMT
Any idea what I can do to get this running?
Edit
The Raw request shows that, as already expected by Jeremy Foster, the client sends a request of the type OPTIONS:
OPTIONS http://localhost:59477/api/fp/get?id=1 HTTP/1.1
Host: localhost:59477
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:4400
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36
Access-Control-Request-Headers: accept, x-zumo-features, x-zumo-installation-id, x-zumo-version
Accept: */*
Referer: http://localhost:4400/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
I managed to support this request applying the [HttpOptions] attribute to my action method. Now I get a more or less valid response:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RjpcQ29kZVxGb290UHJpbnRzXGZvb3RwcmludHMuU2VydmVyXEZvb3RwcmludHNTZXJ2aWNlXGFwaVxmcFxnZXRcMQ==?=
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Date: Sun, 23 Aug 2015 19:34:21 GMT
Content-Length: 234
...
At least that's what fiddler tells me. The AzureMobileServiceClient throws yet another issue, which roughly translates as:
Cross-Origin request blocked, missing token 'x-zumo-installation-id' in CORS header row 'Access-Control-Allow-Headers' on CORS-Preflight-Channel
Turn on Fiddler and try your api call from the browser and then again using the Mobile Services client and compare your raw HTTP requests to see what's different.
Try to run through the CORS Support section of this blog post: http://azure.microsoft.com/blog/2014/07/28/azure-mobile-services-net-updates/.
A side note: The x-zumo-installation-id error you were getting was because the client requested access for a list of headers (see the Access-Control-Request-Headers in your request) and the server did not return that same list in the Access-Control-Allow-Headers header. Using the MS_CrossDomainOrigins setting as mentioned in the above blog post takes care of this by setting the allowed headers to * (all) by default.
I am a novice to angular.js, and I am trying to add some headers to a request:
var config = {headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose'
}
};
$http.get('https://www.example.com/ApplicationData.svc/Malls(1)/Retailers', config).success(successCallback).error(errorCallback);
I've looked at all the documentation, and this seems to me like it should be correct.
When I use a local file for the URL in the $http.get, I see the following HTTP request on the network tab in Chrome:
GET /app/data/offers.json HTTP/1.1
Host: www.example.com
Connection: keep-alive
Cache-Control: max-age=0
If-None-Match: "0f0abc9026855b5938797878a03e6889"
Authorization: Basic Y2hhZHN0b25lbWFuOkNoYW5nZV9tZQ==
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
If-Modified-Since: Sun, 24 Mar 2013 15:58:55 GMT
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
X-Testing: Testing
Referer: http://www.example.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
As you can see, both of the headers were added correctly. But when I change the URL to the one shown in the $http.get above (except using the real address, not example.com), then I get:
OPTIONS /ApplicationData.svc/Malls(1) HTTP/1.1
Host: www.datahost.net
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://mpon.site44.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Access-Control-Request-Headers: accept, origin, x-requested-with, authorization, x-testing
Accept: */*
Referer: http://mpon.site44.com/app/index.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
The only difference in code between these two is one is for the first the URL is a local file, and for the second the URL is a remote server. If you look at the second Request header, there is no Authentication header, and the Accept appears to be using a default instead of the one specified. Also, the first line now says OPTIONS instead of GET (although Access-Control-Request-Method is GET).
Any idea what is wrong with the above code, or how to get the additional headers included using when not using a local file as a data source?
I took what you had, and added another X-Testing header
var config = {headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose',
"X-Testing" : "testing"
}
};
$http.get("/test", config);
And in the Chrome network tab, I see them being sent.
GET /test HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Accept: application/json;odata=verbose
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Authorization: Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==
X-Testing: testing
Referer: http://localhost:3000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Are you not seeing them from the browser, or on the server? Try the browser tooling or a debug proxy and see what is being sent out.
Basic authentication using HTTP POST method:
$http({
method: 'POST',
url: '/API/authenticate',
data: 'username=' + username + '&password=' + password + '&email=' + email,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-Login-Ajax-call": 'true'
}
}).then(function(response) {
if (response.data == 'ok') {
// success
} else {
// failed
}
});
...and GET method call with header:
$http({
method: 'GET',
url: '/books',
headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json',
"X-Login-Ajax-call": 'true'
}
}).then(function(response) {
if (response.data == 'ok') {
// success
} else {
// failed
}
});
If you want to add your custom headers to ALL requests, you can change the defaults on $httpProvider to always add this header…
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common = {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json;odata=verbose'
};
}]);
my suggestion will be add a function call settings like this
inside the function check the header which is appropriate for it. I am sure it will definitely work. it is perfectly working for me.
function getSettings(requestData) {
return {
url: requestData.url,
dataType: requestData.dataType || "json",
data: requestData.data || {},
headers: requestData.headers || {
"accept": "application/json; charset=utf-8",
'Authorization': 'Bearer ' + requestData.token
},
async: requestData.async || "false",
cache: requestData.cache || "false",
success: requestData.success || {},
error: requestData.error || {},
complete: requestData.complete || {},
fail: requestData.fail || {}
};
}
then call your data like this
var requestData = {
url: 'API end point',
data: Your Request Data,
token: Your Token
};
var settings = getSettings(requestData);
settings.method = "POST"; //("Your request type")
return $http(settings);
What you see for OPTIONS request is fine. Authorisation headers are not exposed in it.
But in order for basic auth to work you need to add: withCredentials = true; to your var config.
From the AngularJS $http documentation:
withCredentials - {boolean} - whether to to set the withCredentials
flag on the XHR object. See requests with credentials for more
information.
And what's the answer from the server? It should reply a 204 and then really send the GET you are requesting.
In the OPTIONS the client is checking if the server allows CORS requests. If it gives you something different than a 204 then you should configure your server to send the correct Allow-Origin headers.
The way you are adding headers is the right way to do it.
Chrome is preflighting the request to look for CORS headers. If the request is acceptable, it will then send the real request. If you're doing this cross-domain, you will simply have to deal with it or else find a way to make the request non-cross-domain. This is by design.
Unlike simple requests (discussed above), "preflighted" requests first
send an HTTP request by the OPTIONS method to the resource on the
other domain, in order to determine whether the actual request is safe
to send. Cross-site requests are preflighted like this since they may
have implications to user data. In particular, a request is
preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to
send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted. It sets
custom headers in the request (e.g. the request uses a header such as
X-PINGOTHER)
Ref: AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE?
You are just adding a header which server does not allow.
eg - your server is set up CORS to allow these headers only (accept,cache-control,pragma,content-type,origin)
and in your http request you are adding like this
headers: {
'Authorization': 'Basic d2VudHdvcnRobWFuOkNoYW5nZV9tZQ==',
'Accept': 'application/json',
'x-testing': 'testingValue'
}
then the Server will reject this request since (Authorization and x-testing) are not allowed.
This is server side configuration.
And there is nothing to do with HTTP Options, it is just a preflight to server which is from different domain to check if server will allow actual call or not.
For me the following explanatory snippet worked. Perhaps you shouldn't use ' for header name?
{
headers: {
Authorization: "Basic " + getAuthDigest(),
Accept: "text/plain"
}
}
I'm using $http.ajax(), though I wouldn't expect that to be a game changer.