现象
在以 https 协议页面,以 <img src="http://baidu.com/img/image.png">
方式请求资源时,http 协议的资源地址被转为 https 的。
溯源检查过程
这个问题真的是第一次遇到,本地开发时没发现问题,等到上到测试环境时发现有些图片无法显示。
检查发现 域名用的是https,图片来源有两种,一个是https的,另一个想必大家也猜到了是http的 但之前没发现不能显示啊!
再细查我发现后端给的 http链接 我竟然发的https链接,而图片资源服务器没有做443端口转发,即不支持https链接所以无法获取图片。这时查文档发现大家说是因为前端设置了这个:
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
很显然我的代码中没有,再怀疑是nginx中是不是加了设置,把http转为了https,
第一种方式使用return 301
server {
listen 80;
server_name www.phpmianshi.com;
return 301 https://$http_host$request_uri;
access_log off;
}
第二种方式使用rewrite
server {
listen 80;
server_name www.phpmianshi.com ;
rewrite ^(.*) https://$server_name$1 permanent; #此句最关键
}
第三种方式使用error_page
#使用同一个端口,http转https
原理:
http和https是tcp的上层协议,当nginx服务器建立tcp连接后,根据收到的第一份数据来确定客户端是希望建立tls还是http。nginx会判断tcp请求的首写节内容以进行区分,如果是0x80或者0x16就可能是ssl或者tls,然后尝试https握手。如果端口开启了https,但请求过来的并不是,会抛出一个http级别的错误,这个错误的状态码是NGX_HTTP_TO_HTTPS,错误代码497,然后在返回response中会抛出一个400错误(因为497不是标准状态码,丢给浏览器也没有用),这时浏览器会显示"400 Bad Request,The plain HTTP request was sent to HTTPS port"
server {
listen 80 ssl;
listen www.phpmianshi.com:80; #此处添加你要该链接访问的域名
server_name www.phpmianshi.com ;
error_page 497 https://$host:8080$request_uri; #此句最关键,重新定义端口
#error_page 497 https://$http_host$request_uri; #此句最关键,只是将http改为https,其他不变
}
host:没有端口的server_name :www.phpmianshi.com
http_host:有端口的server_name :www.phpmianshi.com
request_uri:server_name后面的部分 :/?id=297
经检查也是没有,哎,继续查原因,这时测试反馈有的谷歌浏览器可以看到图片而我和另一个主要测试同学不行,查看谷歌浏览器版本,我和另一个主要测试同学是最新版,
最终原因
chrome 新版浏览器会把 http 开头的 url 给重定向到 https 开头的资源 url 上去,若你的资源服务器没有做443端口转发,那就导致资源无法加载。
解决方案
临时解决 - 很显然这个不靠谱,还能挨个让客户改呢
1、地址栏中输入 chrome://net-internals/#hsts
2、在 Delete domain security policies 中输入项目的域名,并 Delete 删除(输入的是http://后面的域名)
3、可以在 Query domain 测试是否删除成功
4、这里如果还是不行, 清除浏览器缓存,然后重启浏览器再试一试。
后端解决 - 不用挣扎这是唯一可行的方案,否则只能放弃新版谷歌浏览器,或者做下兼容处理,在图片不能显示时搞点别的样式放上去
支持 https 请求该资源
谷歌浏览器真是激进啊,别的浏览器暂时没发现这个问题