Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jQuery.ajax doesn’t send headers when ‘dataType‘ is ‘script’ and ‘crossDomain’ is true #5142

Closed
Rinzwind opened this issue Oct 18, 2022 · 6 comments · Fixed by #5193
Assignees
Milestone

Comments

@Rinzwind
Copy link

In the following example, while the same headers setting is used for all four requests, the header is only sent in the first three requests, it is not sent in the fourth request:

const page = 
`<html>
<head>
	<script src='https://code.jquery.com/jquery-3.6.1.min.js'></script>
</head>
<body>
	<script>
		var headers = { 'X-Test-Header': 'Test-Header-Value' };
		$.ajax('Request_1', { dataType: 'html', headers: headers });
		$.ajax('Request_2', { dataType: 'html', crossDomain: true, headers: headers });
		$.ajax('Request_3', { dataType: 'script', headers: headers });
		$.ajax('Request_4', { dataType: 'script', crossDomain: true, headers: headers });
	</script>
</body>
</html>`;
const express = require('express')();
express.get('/', (request, response) => { response.send(page); });
express.get(/^\/Request_[1-4]$/, (request, response) => {
	console.log(`${request.path}: ${request.get('X-Test-Header')}`);
	response.send(''); });
express.listen(9000);

The server logs:

/Request_1: Test-Header-Value
/Request_2: Test-Header-Value
/Request_3: Test-Header-Value
/Request_4: undefined

Shouldn’t the header also be sent in the fourth request?

@mgol
Copy link
Member

mgol commented Nov 18, 2022

Thanks for the report. The script transport has two modes - using a script tag with src or fetching the contents and inserting an inline script (via jQuery.globalEval). The second one requires CORS so the first one is preferred when cross domain. Here are the current conditions:
https://github.com/jquery/jquery/blob/3.6.1/src/ajax/script.js#L47
The code on main (future jQuery 4.0) is a bit more involved:

function canUseScriptTag( s ) {
// A script tag can only be used for async, cross domain or forced-by-attrs requests.
// Sync requests remain handled differently to preserve strict script ordering.
return s.crossDomain || s.scriptAttrs ||
// When dealing with JSONP (`s.dataTypes` include "json" then)
// don't use a script tag so that error responses still may have
// `responseJSON` set. Continue using a script tag for JSONP requests that:
// * are cross-domain as AJAX requests won't work without a CORS setup
// * have `scriptAttrs` set as that's a script-only functionality
// Note that this means JSONP requests violate strict CSP script-src settings.
// A proper solution is to migrate from using JSONP to a CORS setup.
( s.async && jQuery.inArray( "json", s.dataTypes ) < 0 );
}

We should investigate adding headers to the list.

I wonder if this would be a breaking change for 3.x? We'll discuss this at the team's meeting.

@mgol mgol added Ajax Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. labels Nov 18, 2022
@timmywil timmywil removed the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Nov 21, 2022
@timmywil timmywil added this to the 4.0.0 milestone Nov 21, 2022
@mgol mgol self-assigned this Jan 12, 2023
mgol added a commit to mgol/jquery that referenced this issue Jan 12, 2023
The AJAX script transport has two versions: XHR + `jQuery.globalEval` or
appending a script tag (note that `jQuery.globalEval` also appends a
script tag now, but inline). The former cannot support the `headers`
option which has so far not been taken into account.

For jQuery 3.x, the main consequence was the option not being respected
for cross-domain requests. Since in 4.x we use the latter way more
often, the option was being ignored in more cases.

The transport now checks whether the `headers` option is specified and
uses the XHR way unless `scriptAttrs` are specified as well.

Fixes jquerygh-5142
mgol added a commit to mgol/jquery that referenced this issue Jan 12, 2023
The AJAX script transport has two versions: XHR + `jQuery.globalEval` or
appending a script tag (note that `jQuery.globalEval` also appends a
script tag now, but inline). The former cannot support the `headers`
option which has so far not been taken into account.

For jQuery 3.x, the main consequence was the option not being respected
for cross-domain requests. Since in 4.x we use the latter way more
often, the option was being ignored in more cases.

The transport now checks whether the `headers` option is specified and
uses the XHR way unless `scriptAttrs` are specified as well.

Fixes jquerygh-5142
@mgol
Copy link
Member

mgol commented Jan 12, 2023

PR: #5193

@mgol mgol closed this as completed in #5193 Feb 1, 2023
mgol added a commit that referenced this issue Feb 1, 2023
The AJAX script transport has two versions: XHR + `jQuery.globalEval` or
appending a script tag (note that `jQuery.globalEval` also appends a
script tag now, but inline). The former cannot support the `headers`
option which has so far not been taken into account.

For jQuery 3.x, the main consequence was the option not being respected
for cross-domain requests. Since in 4.x we use the latter way more
often, the option was being ignored in more cases.

The transport now checks whether the `headers` option is specified and
uses the XHR way unless `scriptAttrs` are specified as well.

Fixes gh-5142
Closes gh-5193
@mgol
Copy link
Member

mgol commented Feb 1, 2023

For jQuery 4.0, this will be fixed via #5193. For jQuery 3.x, you can workaround by setting crossDomain to false, even if the request is cross-domain.

@idiamant
Copy link

Trying with jQuery 3.7.1 to use $.ajax with dataType: jsonp (since it's a crossdomain request), and I need to authenticate with some header. I add the headers parameter, and it's not being passed with the request, and therefore my request fails on authentication.

When I disable crossDomain / jsonp, the request is failing on CORS, but the header IS being sent.

Why is that? How can I force it to send the headers with the request using jsonp datatype?

@mgol
Copy link
Member

mgol commented Jan 23, 2024

@idiamant JSONP is generally meant to be used via script tags where you have no control over special headers. If the server supports cross-domain XHR, it has to have a working CORS setup. In that case, why even use JSONP which is a hacky insecure workaround for infrastructure without CORS?

This looks to me like a question better suited for Stack Overflow. Otherwise, please submit a new detailed issue with a test case. I don’t think we’re likely to be looking at a jQuery issue here, though.

@idiamant
Copy link

@mgol The issue I was facing is building some web interface which queries a 3rd party service for some data.

Since this is a 3rd party, I don't control it's CORS settings.

For now I've implemented a backend "proxy" solution, which will perform the query on the backend side, and provide me with results locally to my server's frontend.

Tried to avoid using a backend solution for this implementation I'm doing, and only use frontend (allowing me a cheaper hosting of the solution, through some static files bucket).

If you think this is not relevant, then you may ignore this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

4 participants