Skip to content

Commit fbfea0f

Browse files
RuslanZavackykamilogorek
authored andcommitted
feat: Ability to specify Custom headers (#1166)
* Ability to specify custom headers for request (#1166) * Add headers for fetch() method (#1166) * Update tests for the evaluating headers (#1166) * Add TS type for headers (#1166) * Add `headers` to documentation (#1166) * Add `headers: null` to global options default definition (#1166) * Describe `options` for transport method (#1166)
1 parent 1956b18 commit fbfea0f

File tree

4 files changed

+112
-4
lines changed

4 files changed

+112
-4
lines changed

docs/config.rst

+29
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,41 @@ Those configuration options are documented below:
269269
sentry_key
270270
Your public client key (DSN).
271271

272+
options
273+
Include all top-level options described.
274+
272275
onSuccess
273276
Callback to be invoked upon a successful request.
274277

275278
onError
276279
Callback to be invoked upon a failed request.
277280

281+
.. describe:: headers
282+
283+
Pass custom headers to server requests for ``fetch`` or ``XMLHttpRequest``.
284+
285+
.. code-block:: javascript
286+
287+
{
288+
headers: {
289+
'CSRF-TOKEN': '12345'
290+
}
291+
}
292+
293+
Headers value can be in form of a function, to compute value in time of a request:
294+
295+
.. code-block:: javascript
296+
297+
{
298+
headers: {
299+
'CSRF-TOKEN': function() {
300+
// custom logic that will be computed on every request
301+
return new Date();
302+
}
303+
}
304+
}
305+
306+
278307
.. describe:: allowDuplicates
279308

280309
By default, Raven.js attempts to suppress duplicate captured errors and messages that occur back-to-back. Such events are often triggered by rogue code (e.g. from a `setInterval` callback in a browser extension), are not actionable, and eat up your event quota.

src/raven.js

+36-4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ function Raven() {
7474
ignoreUrls: [],
7575
whitelistUrls: [],
7676
includePaths: [],
77+
headers: null,
7778
collectWindowErrors: true,
7879
maxMessageLength: 0,
7980

@@ -1897,12 +1898,23 @@ Raven.prototype = {
18971898
// Auth is intentionally sent as part of query string (NOT as custom HTTP header) to avoid preflight CORS requests
18981899
var url = opts.url + '?' + urlencode(opts.auth);
18991900

1901+
var evaluatedHeaders = null;
1902+
if (opts.options.headers) {
1903+
evaluatedHeaders = this._evaluateHeaders(opts.options.headers);
1904+
}
1905+
19001906
if (supportsFetch()) {
1907+
var fetchOptions = {
1908+
method: 'POST',
1909+
body: stringify(opts.data)
1910+
};
1911+
1912+
if (evaluatedHeaders) {
1913+
fetchOptions.headers = evaluatedHeaders;
1914+
}
1915+
19011916
return _window
1902-
.fetch(url, {
1903-
method: 'POST',
1904-
body: stringify(opts.data)
1905-
})
1917+
.fetch(url, fetchOptions)
19061918
.then(function(response) {
19071919
if (response.ok) {
19081920
opts.onSuccess && opts.onSuccess();
@@ -1960,9 +1972,29 @@ Raven.prototype = {
19601972
}
19611973

19621974
request.open('POST', url);
1975+
1976+
if (evaluatedHeaders) {
1977+
each(evaluatedHeaders, function(key, value) {
1978+
request.setRequestHeader(key, value);
1979+
});
1980+
}
1981+
19631982
request.send(stringify(opts.data));
19641983
},
19651984

1985+
_evaluateHeaders: function(headers) {
1986+
var evaluatedHeaders = {};
1987+
1988+
for (var key in headers) {
1989+
if (headers.hasOwnProperty(key)) {
1990+
var value = headers[key];
1991+
evaluatedHeaders[key] = typeof value === 'function' ? value() : value;
1992+
}
1993+
}
1994+
1995+
return evaluatedHeaders;
1996+
},
1997+
19661998
_logDebug: function(level) {
19671999
if (this._originalConsoleMethods[level] && this.debug) {
19682000
// In IE<10 console methods do not have their own 'apply' method

test/raven.test.js

+42
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,48 @@ describe('globals', function() {
13921392
});
13931393
});
13941394

1395+
it('should apply globalOptions.headers if specified', function() {
1396+
this.sinon.stub(Raven, 'isSetup').returns(true);
1397+
this.sinon.stub(window, 'fetch').resolves(true);
1398+
1399+
Raven._globalProject = '2';
1400+
Raven._globalOptions = {
1401+
logger: 'javascript',
1402+
maxMessageLength: 100,
1403+
headers: {
1404+
'custom-header': 'value'
1405+
}
1406+
};
1407+
1408+
Raven._send({message: 'bar'});
1409+
1410+
assert.deepEqual(window.fetch.lastCall.args[1].headers, {
1411+
'custom-header': 'value'
1412+
});
1413+
});
1414+
1415+
it('should apply globalOptions.headers with function value if specified', function() {
1416+
this.sinon.stub(Raven, 'isSetup').returns(true);
1417+
this.sinon.stub(window, 'fetch').resolves(true);
1418+
1419+
Raven._globalProject = '2';
1420+
Raven._globalOptions = {
1421+
logger: 'javascript',
1422+
maxMessageLength: 100,
1423+
headers: {
1424+
'custom-header': function() {
1425+
return 'computed-header-value';
1426+
}
1427+
}
1428+
};
1429+
1430+
Raven._send({message: 'bar'});
1431+
1432+
assert.deepEqual(window.fetch.lastCall.args[1].headers, {
1433+
'custom-header': 'computed-header-value'
1434+
});
1435+
});
1436+
13951437
it('should check `Raven.isSetup`', function() {
13961438
this.sinon.stub(Raven, 'isSetup').returns(false);
13971439
this.sinon.stub(Raven, '_makeRequest');

typescript/raven.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ declare module Raven {
6363
/** Override the default HTTP data transport handler. */
6464
transport?: (options: RavenTransportOptions) => void;
6565

66+
/** Append headers to the fetch or XMLHttpRequest request. Should be in a form of hash, were value can be string or function */
67+
headers?: {
68+
[key: string]: (string | Function);
69+
};
70+
6671
/** Allow use of private/secretKey. */
6772
allowSecretKey?: boolean;
6873

0 commit comments

Comments
 (0)