更换完https,成功运行了大概三到四天,突然出现混合请求(https请求包含了http,被浏览器拦截),贼迷。。。
故事背景
为了服务器能接入百度的智能语音api,支持https是必须的。既然给域名申请了ssl证书,那索性把博客也改成https访问。
然后就开始一通配置,因为这个放博客的vps使用的是cpanel控制面板,所以权限是被限制的,但搭博客啥的就很方便,环境都配好了,控制面板也提供了包管理,快速安装相关软件,自动管理ssl证书,重定向,子域名等等。
ps:这里的重定向可以用来代替域名解析的显性url(如果你的域名没有备案的话)
所以就在控制面板上开启了ssl和https访问,然后把所有http访问重定向成https,在wordpress管理控制台把域名也改成https,然后就能成功挂上小锁了!!
但是,问题又来了,在成功运行了大概三到四天之后,突然出现混合请求(https请求包含了http,被浏览器拦截) 。我:??????。
我这啥也没动啊怎么就这样了?而且前面不是跑得好好的?
排查问题
于是先f12,看看哪里出现了混合请求,发现是各个页面的模板里都出现了http引用。各种css和图片都是http的链接,文章部分又是好的。
我又:????那前面为啥跑得好好的。
于是排查了一下所使用的主题内部有没有使用了http的硬链接,结果并没有。
于是怀疑一下wordpress本身的链接是否出现了http的绝对路径,但因为在控制台已经把站点地址修改成https了,感觉没太大可能性。
于是又把wordpress的数据库打开,执行替换,把所有http替换成https。然并卵,而且并没有相关的条目。
我继续:?????那为啥前面跑得好好的。
于是我在绝望中选择备份并重装。。。一样的问题。。
啊。。。鲨了我吧
问题解决
最后死马当活马医,搜了n多教程,说啥没强制开启ssl访问。于是我就不抱希望的试了一下:
- 打开wordpress根目录, wp-config.php。
- 添加以下内容
$_SERVER['HTTPS'] = 'on';
define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);
- 保存
然后。。就成了?????
我更:??????了
解决之后
最后发现问题出在$_SERVER['HTTPS'] = 'ON';
这条语句上,直接设置环境变量。通过查询相关案例,有出现过同一台服务器上通过$_SERVER
拿到的环境变量有的是https,有的是null,这样也就导致某些使用了相对路径的请求使用了http。
这样在设置之后,即使是通过http访问,内部的资源也全部都是https链接的。
这种问题的实质还是服务器上的fastcgi配置有问题,如果使用了nginx, 默认不会将HTTPS
传递给PHP-FPM
,也就拿不到环境变量。但apache就可以。 (本机上无权限,无法测试) 这里贴出其他人的配置。
nginx样例例:
location ~ .*\.(php|php5)?$
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_index index.php;
include fastcgi_params;
}
其中fastcgi_param HTTPS $https if_not_empty;
这一条就是设置环境变量。意思就是查询链接类型,如果为空,则忽略。
如果想网站强制https访问,则可以把这条变量写死,变成:
<strong>FASTCGI_PARAM HTTPS </strong>on
这和在wordpress里把环境变量写死是一个道理。但在这里改会对所有使用了该环境变量的程序生效。
方法汇总
在服务器ssl证书配置完毕的前提下,开始对wordpress进行修改。
- 在wordpress 的管理页面,把站点地址修改成https协议的,同步更改站点内的链接地址,媒体地址。
- 找到网站根目录,修改 wp-config.php,添加以下条目。
$_SERVER['HTTPS'] = 'ON';
DEFINE('FORCE_SSL_LOGIN', TRUE);
DEFINE('FORCE_SSL_ADMIN', TRUE);
- 数据库替换,防止旧链接仍然是http协议的 :(不推荐这样操作)
<strong>update wp_posts set post_content = replace(post_content, 'http://example.com','https://example.com'); </strong>
- wp主题内链接替换(可代替数据库替换)
编辑当前主题下的 functions.php 文件,加入以下代码:
//绝对路径替换
add_filter('get_header', 'fanly_ssl');
function fanly_ssl(){
if( is_ssl() ){
function fanly_ssl_main ($content){
$siteurl = get_option('siteurl');
$upload_dir = wp_upload_dir();
$content = str_replace( 'http:'.strstr($siteurl, '//'), 'https:'.strstr($siteurl, '//'), $content);
$content = str_replace( 'http:'.strstr($upload_dir['baseurl'], '//'), 'https:'.strstr($upload_dir['baseurl'], '//'), $content);
return $content;
}
ob_start("fanly_ssl_main");
}
}
//相对路径替换
add_filter('get_header', 'fanly_ssl');
function fanly_ssl(){
if( is_ssl() ){
function fanly_ssl_main ($content){
$siteurl = get_option('siteurl');
$upload_dir = wp_upload_dir();
$content = str_replace( 'http:'.strstr($siteurl, '//'), strstr($siteurl, '//'), $content);
$content = str_replace( 'http:'.strstr($upload_dir['baseurl'], '//'), strstr($upload_dir['baseurl'], '//'), $content);
return $content;
}
ob_start("fanly_ssl_main");
}
}
- nginx配置文件修改(别照搬,这里只是样例),重点是
fastcgi_param HTTPS $https if_not_empty;
location ~ .*\.(php|php5)?$
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_index index.php;
include fastcgi_params;
}
叨叨几句... NOTHING