Related
I am running a Python Flask server. A co-worker added Flasgger/Swagger support and I can successfully display the API using
http://localhost:5000/apidocs
Similarly, I can get the json version of the API
http://localhost:5000/api_documentation.json
Python code configures that filename
That same code is deployed in an Openshift project and uses Traefik to route external requests to the Python Flask server
https://my-openshift-url-here/apidocs
does not display the API
only displays "Powered by Flasgger 0.9.5
https://my-openshift-url-here/api_documentation.json
works same as the localhost request
Traefik keys off of the "apidocs" and "api_documentation.json" and routes it directly to the Python Flask server
rule: PathPrefix(`/apidocs`)
entryPoints:
- web
middlewares:
- gzip
- mysecurity-no-token
service: my-python-server
apidocumentation:
rule: PathPrefix(`/api_documentation.json`)
entryPoints:
- web
middlewares:
- gzip
- mysecurity-no-token
service: my-python-server
What I see in my Chrome browser debugger (F12 - Network) for the swagger-ui-bundle.js response is "You need to enable JavaScript to run this app."
Why does this work in Chrome for the localhost version but not when accessing the server deployed on Openshift? Both are being accessed from the same Chrome window - just different tabs.
This is the Headers content of the apidocs request for the localhost version
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:5000
Referrer Policy: strict-origin-when-cross-origin
Content-Length: 3041
Content-Type: text/html; charset=utf-8
Date: Thu, 19 Aug 2021 12:08:41 GMT
Server: Werkzeug/2.0.1 Python/3.7.4
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:5000
Pragma: no-cache
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
This is the Headers content of the apidocs request for the Openshift version
Request Method: GET
Status Code: 200 OK
Remote Address: 123.456.789.123:443 (obfuscated, of course)
Referrer Policy: origin
content-encoding: gzip
content-length: 1264
content-type: text/html; charset=utf-8
date: Thu, 19 Aug 2021 12:08:59 GMT
server: istio-envoy
vary: Accept-Encoding
x-envoy-upstream-service-time: 28
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: no-cache
Connection: keep-alive
Host: my-openshift-server-url-here
Pragma: no-cache
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Turns out it was a Traefik routing issues. After the initial response to the /apidocs request, it was also making requests to /flasgger_static/foo. I had to add a route for flassgger_static in my Traefik routing table.
flassger:
rule: PathPrefix(`/flasgger_static`)
entryPoints:
- web
middlewares:
- gzip
- mysecurity-no-token
service: my-python-server
Please help me to find an appropriate solution for Edge browser.
I found that Edge browser doesn't follow the Location header in case of HTTP 302 Found response both for GET and POST requests.
In short, the same code (see the explanation below):
works perfectly in FF/Chrome (all the headers are set for the initial call, the headers/cookies are set and sent for all redirected calls as well)
Edge browser ignores Location header / HTTP 302 response code (no redirect at all).
IE 11 browser ignores the header we set for the initial call (Content-Type) in the redirected call
page opened: https://example.com
async GET call made to https://some-service.io/login with custom headers set
Content-Type = application/json; charset=utf-8
X-Header = http://some-service.io/xxx-yyy-zzz
Note: different domains are used for the page and for the service
and with withCredentials enabled because of CORS, data attribute has an empty object (for axios call) or some dummy data (for javascript call) as we had an issue in Chrome/FF with headers for the redirected call:
Javascript version
function httpGetAsync(url, method, callback) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function ()
{
if (xmlHttp.readyState == XMLHttpRequest.DONE && xmlHttp.status == 200) {
console.log('DONE');
callback(xmlHttp.readyState + ':' + xmlHttp.status + ':' + xmlHttp.response);
return;
}
console.log(xmlHttp.readyState + ':' + xmlHttp.status + ':' + xmlHttp.response);
var headers = xmlHttp.getAllResponseHeaders();
console.log('headers: ' + headers.toString());
}
xmlHttp.open(method, url, true); // true for asynchronous
xmlHttp.withCredentials = true;
xmlHttp.setRequestHeader('Accept', 'application/json');
xmlHttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xmlHttp.setRequestHeader('X-Header', 'https://some-service.io/xxx-yyy-zzz');
xmlHttp.send("foo=bar&lorem=ipsum");
}
httpGetAsync('https://some-service.io/login', 'GET', function (response) {
console.log(response);
});
AXIOS version
...
defaultHeaders['Content-Type'] = 'application/json;charset=UTF-8';
defaultHeaders['X-Header'] = 'https://some-service.io/xxx-yyy-zzz';
...
axios({
method: 'GET',
url: 'https://some-service.io/login',
withCredentials: true,
headers: defaultHeaders,
data: {}
}).then(response => {
...
Server responds with HTTP 302, with Set-Cookie and Location: https://some-service.io/login/auth headers in the response, we need to send original headers and the cookies set with the redirected call to https://some-service.io/login/auth
For the redirected call to https://some-service.io/login/auth server responds with HTTP 200,
json-object returned in case if Content-Type is set in request headers:
Chrome/FF works perfectly, follow the redirects, the headers from the initial call are available for the redirected call as well, HTTP 200 returned with the valid json-object
Edge browser doesn't follow Location header value at all
IE 11 browser follow the redirect url from Location header but without Headers set in the initial call (added just for comparison)
RAW HTTP
Edge
-- OPTIONS (preflight)
OPTIONS https://some-service.io/login HTTP/1.1
Origin: https://example.com
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
Access-Control-Request-Headers: content-type,database,dictionarydomain,language,site,x-referer-epay
Access-Control-Request-Method: GET
Accept: */*
Accept-Language: en-US,en;q=0.8,cs;q=0.6,ru;q=0.4,uk;q=0.2
Accept-Encoding: gzip, deflate, br
Host: some-service.io
Content-Length: 0
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache
-- GET Request
GET https://some-service.io/login HTTP/1.1
Origin: https://example.com
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.8,cs;q=0.6,ru;q=0.4,uk;q=0.2
Content-Type: application/json;charset=UTF-8
X-Header: https://some-service.io/xxx-yyy-zzz
Accept-Encoding: gzip, deflate, br
Host: some-service.io
DNT: 1
Connection: Keep-Alive
-- GET Response
HTTP/1.1 302 Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Date: Tue, 10 Dec 2019 12:26:08 GMT
Expires: 0
Location: https://some-service.io/login/auth
Pragma: no-cache
Set-Cookie: JSESSIONID=CC10DD73C968C42C5A007D27342BF0B5; Path=/; Secure
Set-Cookie: __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7; Path=/; HttpOnly; Secure
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: ef27c9ae-fa5b-45b6-5c6a-9537b159e533
X-Xss-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive
-- GET Request for redirected call (https://some-service.io/login/auth, missing)
Chrome
-- OPTIONS (preflight)
OPTIONS https://some-service.io/login HTTP/1.1
Host: some-service.io
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Access-Control-Request-Headers: content-type,database,dictionarydomain,language,site,x-referer-epay
Accept: */*
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6
-- GET Request
GET https://some-service.io/login HTTP/1.1
Host: some-service.io
Connection: keep-alive
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
X-Header: https://some-service.io/xxx-yyy-zzz
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6
Cookie: JSESSIONID=998B805DAF1BBA4C76AB930702C49131; __VCAP_ID__=a3ed6e06-6e23-43ad-469a-e848
-- GET Response
HTTP/1.1 302 Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Date: Tue, 10 Dec 2019 10:33:02 GMT
Expires: 0
Location: https://some-service.io/login/auth
Pragma: no-cache
Set-Cookie: __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7; Path=/; HttpOnly
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: e207bdaa-20a6-48a1-7f97-b0688d2f1f98
X-Xss-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive
-- GET Request for redirected call (https://some-service.io/login/auth)
GET https://some-service.io/login/auth HTTP/1.1
Host: some-service.io
Connection: keep-alive
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
Database: master
X-Header: https://some-service.io/xxx-yyy-zzz
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6
Cookie: JSESSIONID=998B805DAF1BBA4C76AB930702C49131; __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7
-- GET Response
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Tue, 10 Dec 2019 10:35:35 GMT
Expires: 0
Pragma: no-cache
Set-Cookie: __VCAP_ID__=a3ed6e06-6e23-43ad-469a-e848; Path=/; HttpOnly
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: ad084e82-1038-4953-5f40-cfcf4f4c10d3
X-Xss-Protection: 1; mode=block
Content-Length: 16
Connection: keep-alive
{"some-value":0}
Notes
the main difference between Edge and Chrome - these two headers
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Edge/18.18362
Chrome/78.0.3904.108
In order to mitigate CORS implementation differences for different browsers, I decided to move CORS requests from FE side to BE side.
Small transparent proxy has been implemented to serve requests from FE to BE and call Service from BE using RestClient (or HttpClient) component which works perfectly with CORS and redirected calls in comparison with direct calls from FE to Service.
I am trying to make a Cross Origin delete request via fetch and its failing with a 403 (Exact Error Access to fetch at 'http://localhost:1180/api/deleteResource/name/something/city/Shenzhen%202' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.)
Here are my request and response headers -
General -
Request URL: http://localhost:1180/api/deleteResource/name/something/city/Shenzhen%202
Request Method: OPTIONS
Status Code: 403 FORBIDDEN
Remote Address: [::1]:1180
Referrer Policy: no-referrer-when-downgrade
Response Headers-
Access-Control-Allow-Credentials: false
Access-Control-Allow-Headers: Content-Type,Content-Length,Server,Date
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Type, Content-Length, Server, Date
Content-Length: 43
Content-Type: application/json
Content-Type: application/json; charset=utf-8
Date: Mon, 18 Nov 2019 07:24:51 GMT
Server: Werkzeug/0.14.1 Python/3.6.5
X-Content-Type-Options: nosniff
Request headers-
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: access-control-allow-methods,access-control-allow-origin
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: localhost:1180
Origin: http://localhost:3000
Referer: http://localhost:3000/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36
Whereas my GET requests are working just fine -
General -
Request URL: http://localhost:1180/api/getResources
Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:1180
Referrer Policy: no-referrer-when-downgrade
Response Headers -
Access-Control-Allow-Credentials: false
Access-Control-Allow-Headers: Content-Type,Content-Length,Server,Date
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Type, Content-Length, Server, Date
Content-Length: 6164
Content-Type: application/json
Content-Type: application/json; charset=utf-8
Date: Mon, 18 Nov 2019 07:24:44 GMT
Server: Werkzeug/0.14.1 Python/3.6.5
X-Content-Type-Options: nosniff
Request Headers -
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: localhost:1180
Origin: http://localhost:3000
Referer: http://localhost:3000/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36
I do understand that the preflight check doesn't happen for Simple GET & POST requests due to which my GET is successful, but still I don't get why my DELETE is failing as it has been allowed from the server. Can someone help me understand what the problem here is?
Your DELETE request has access-control-allow-methods,access-control-allow-origin headers, But In response, It only allows Content-Type, Content-Length, Server, Date headers. That's why it's throwing doesn't pass access control error.
Solution
Set Access-Control-Allow-Headers to allow Content-Type,Content-Length,Server,Date,access-control-allow-methods,access-control-allow-origin.
I am not sure about your Back-End technology, I can't provide code to allow above headers without knowing your back-end technology
I'm providing an ETag in the Response Header from the server to the browser when supplying a javascript file generated programatically.
On subsequent requests for that same javascript file the ETag does not get supplied back in Request Header by the browser.
I've tried this in both Chrome and IE, same results find below the request and response headers from original request and subsequent one.
Original Request Header
GET /v11/RUNTIME_SUPPORT.GetGlobalFormResources.aspx HTTP/1.1
Host: 101.152.80.163
Connection: keep-alive
Cache-Control: max-age=0
Accept: */*
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.66 Safari/537.36
Referer: http://101.152.80.163/v11/Web_Support.Html.aspx
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ro;q=0.6,es;q=0.4
Cookie: StaraspxOpenTabsCount=0; ASP.NET_SessionId=jpdkfccaf0zttoxyvys53ac3; STARaspx_SessionId=1006606D-F415-4AE5-AA4C-847625EB2BAE
If-None-Match: 0.0.459
Original Response Header
HTTP/1.1 200 OK
Cache-Control: public, max-age=604800
Content-Type: application/javascript; charset=utf-8
Content-Encoding: gzip
ETag: 0.0.459,0.0.0,0.00
Vary: Accept-Encoding
Server: Microsoft-IIS/8.5
ItemType: FORMS
Digest: e0d3a2bdee4c0a48bc4f61bb744755c21c1d6c19
X-Powered-By: ASP.NET
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
Access-Control-Allow-Headers: callfrom, content-type, runtimecalltype
Access-Control-Allow-Credentials: true
Date: Tue, 12 Apr 2016 11:46:06 GMT
Content-Length: 31763
Subsequent Request Header
GET /v11/RUNTIME_SUPPORT.GetGlobalFormResources.aspx HTTP/1.1
Host: 101.152.80.163
Connection: keep-alive
Cache-Control: max-age=0
Accept: */*
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.66 Safari/537.36
Referer: http://101.152.80.163/v11/Web_Support.Html.aspx
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,ro;q=0.6,es;q=0.4
Cookie: StaraspxOpenTabsCount=0; ASP.NET_SessionId=jpdkfccaf0zttoxyvys53ac3; STARaspx_SessionId=1006606D-F415-4AE5-AA4C-847625EB2BAE
If-None-Match: 0.0.459
Subsequent Response Header
HTTP/1.1 200 OK
Cache-Control: public, max-age=604800
Content-Type: application/javascript; charset=utf-8
Content-Encoding: gzip
ETag: 0.0.459,0.0.0,0.00
Vary: Accept-Encoding
Server: Microsoft-IIS/8.5
ItemType: FORMS
Digest: e0d3a2bdee4c0a48bc4f61bb744755c21c1d6c19
X-Powered-By: ASP.NET
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
Access-Control-Allow-Headers: callfrom, content-type, runtimecalltype
Access-Control-Allow-Credentials: true
Date: Tue, 12 Apr 2016 11:46:48 GMT
Content-Length: 31763
I've identified the root causes for ETags not working in my scenario:
I should have looked at the If-None-Match request header field rather than expecting an ETag field be provided to the server (more details here Header Field Definitions)
I should have not used commas in my ETag respose header field value, only the sub-string before the first comma gets sent back in request header field If-None-Match. In my case the ETag value in respose header was 0.0.459,0.0.0,0.00 and the subsequent request had 0.0.459 in the If-None-Match header field.
Response header from server now: HTTP/1.1 304 Not Modified :)
I'm trying to get Chrome Logger working in an Angular app running against a PHP backend, but for some reason the X-ChromeLogger-Data header doesn't seem to be coming through when the API is accessed by the Angular app.
If I open the API's access point directly or hit it with a jQuery.get() request everything works fine, even if I make the ajax request from another domain. The API also works correctly otherwise, even when used by the Angular app. It's just that one header disappears somewhere along the way. It doesn't even appear in Chrome's console.
What could cause a header to disappear?
Here's a request made with jQuery.get()
Request:
GET /?action=load HTTP/1.1
Host: -
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
Origin: -
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36
Referer: -
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fi-FI,fi;q=0.8,en-US;q=0.6,en;q=0.4,sv;q=0.2
Response:
HTTP/1.1 200 OK
Date: Sat, 07 Nov 2015 10:41:22 GMT
Server: Apache/2.4.12 (Ubuntu)
X-Powered-By: PHP/5.6.11-1ubuntu3.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, X-ChromeLogger-Data
X-ChromeLogger-Data: eyJ2ZXJzaW9uIjoiNC4wIiwiY29sdW1ucyI6WyJsYWJlbCIsImxvZyIsImJhY2t0cmFjZSIsInR5cGUiXSwicm93cyI6W1siQVBJIiwiQVBJIHJlYWNoZWQiLCJ1bmtub3duIiwid2FybiJdXSwicmVxdWVzdF91cmkiOiJcLz9hY3Rpb249bG9hZCJ9
Content-Length: 15
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
And here's one from the Angular app:
Request:
GET /?action=load HTTP/1.1
Host: -
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: -
X-FirePHP-Version: 0.0.6
User-Agent: Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Referer: -
Accept-Encoding: gzip, deflate, sdch
Accept-Language: fi-FI,fi;q=0.8,en-US;q=0.6,en;q=0.4,sv;q=0.2
Response:
HTTP/1.1 200 OK
Date: Sat, 07 Nov 2015 10:34:33 GMT
Server: Apache/2.4.12 (Ubuntu)
X-Powered-By: PHP/5.6.11-1ubuntu3.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, X-ChromeLogger-Data
Content-Length: 15
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
The Angular code used to make the above request:
$http.get( endpoint, { params : { action : 'load' } } ).then(
function( response ) {
console.log( response );
},
function() {
console.log( 'fail' );
}
);
After Dvir's tip to further inspect the differences between the requests (with the aid of Fiddler) I finally manager to solve the problem. I was running the Angular app with Chrome's mobile device simulator turned on, and it turns out the Monolog ChromePHPHandler requires for the text "Chrome" to be present in the User-Agent header, which it wasn't when the simulator was turned on.