One of the reasons why you may see the
ERR_SPDY_PROTOCOL_ERROR message is an invalid HTTP header coming from the server. Chrome is a bit more strict when processing binary HTTP/2, can't handle a header with a space instead of a dash (e.g.
Referrer Policy instead of
Referrer-Policy), so check your headers are being sent correctly. Firefox ignores such invalid HTTP header and will just display the page.
Here's how to find the offending header. Go to
chrome://net-internals/#events (the link is not clickable, but you can just copy and paste it), type your domain into the search box there (I'll use
example.com as, well, an example), then try loading your misbehaving site in a different tab. Go back to
chrome://net-internals/#events and click the row with
HTTP2_SESSION in Source Type column.
On the right side, you'll see an HTTP/2 protocol details, this is the important part:
t=50413 [st=7] HTTP2_SESSION_RECV_INVALID_HEADER --> header_name = "referrer policy" --> header_value = "same-origin" t=50413 [st=7] HTTP2_SESSION_SEND_RST_STREAM --> description = "Could not parse Spdy Control Frame Header." --> error_code = "1 (PROTOCOL_ERROR)" --> stream_id = 3
See the line with
HTTP2_SESSION_RECV_INVALID_HEADER? There's an invalid header just below it, in this case it's the
referrer policy header, with space instead of dash. Header names in HTTP/2 must be converted to lowercase, so even if you send
Referrer-Policy from your app, the browser sees
referrer-policy. Or invalid
referrer policy in this case.
You'll find a lot of interesting things about your browser internals in
chrome://net-internals/. There are requests which are not even displayed in Developer Tools, like the ones coming from extensions. Go and check it out, might be handy next time you need to debug something. I've used it when researching Opera browser “VPN” or unencrypted “VPN” in UR browser.