
什么是混合内容?
混合内容是指网页通过HTTPS加载,但包含通过HTTP(未加密)加载的资源——如图像、JavaScript文件、CSS样式表或iframe的情况。尽管主页面URL是https://,但浏览器无法确认整个页面是安全的,因为某些元素来自不安全的通道。
结果是:即使您安装了SSL证书且网站在https://上加载,挂锁图标也可能不会出现,或者可能显示警告图标。某些用户可能会看到"不安全"指示符。这是混合内容在起作用,而不是您的SSL证书本身的问题。
两种类型的混合内容
1. 被动混合内容(警告)
通过HTTP加载但无法直接修改页面内容的资源,如图像(<img>)、视频和音频。浏览器显示警告但仍然加载这些资源,因为风险级别较低。但挂锁通常会显示信息或警告图标,而不是安全挂锁。
示例:HTTPS页面通过http://example.com/photo.jpg从另一个域嵌入图像
2. 主动混合内容(被阻止)
可以修改或控制页面DOM的资源——JavaScript(<script>)、CSS(<link rel="stylesheet">)、iframe和XMLHttpRequest。浏览器完全阻止这些,因为它们代表高安全风险。被阻止的主动混合内容可能导致您页面上的功能无声地中断。
最常见原因:将网站从HTTP迁移到HTTPS而不更新数据库或代码中的所有资源URL。即使SSL已安装,图像、脚本和链接仍然指向http:// URL。
主动与被动混合内容:有什么区别
许多人困惑为什么一些包含混合内容的页面仍然正常打开(只是没有挂锁),而其他页面完全中断。答案在于HTTP资源是被动还是主动,因为浏览器对两个类别的处理方式完全不同。了解这一区别可以帮助您正确确定修复优先级,避免浪费时间先追逐低影响问题。
被动混合内容是只"显示"但无法控制页面的内容——图像、视频和音频。即使通过HTTP加载,浏览器也允许它们加载,因为风险有限。进行中间人攻击的攻击者最多只能交换图像或观察用户正在查看的内容。然而,结果是浏览器降低整个页面的安全状态:挂锁消失,出现"不完全安全"警告。
主动混合内容是可以"控制"页面的内容——JavaScript、CSS、iframe、fetch/XMLHttpRequest和网络字体。如果攻击者拦截并替换通过HTTP加载的脚本,他们可以在您的页面上运行任意代码、窃取cookie、改变内容或将用户重定向到假页面。由于这一高风险,现代浏览器(Chrome、Firefox、Edge、Safari)完全阻止它,无需询问。结果是样式中断、按钮不起作用或表单无法提交。
| 方面 | 被动 | 主动 |
|---|---|---|
| 资源示例 | img、视频、音频 | script、CSS链接、iframe、fetch |
| 浏览器行为 | 加载+警告 | 完全阻止 |
| 影响 | 挂锁丢失 | 功能和样式损坏 |
| 紧急程度 | 中等 | 非常高 |
In short, active mixed content must always be fixed first because it breaks the site's actual functionality. Passive content should be fixed too so the padlock returns, but it won't take the site down. A good approach is to start with scripts and CSS, then move on to images and media afterward.
Finding Mixed Content with the Browser Console and Why No Padlock
Using Browser DevTools
- Open your webpage in Chrome
- Press F12 or right-click → Inspect to open DevTools
- Click the Console tab
- Look for red or yellow messages starting with "Mixed Content:" such as: "Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...'"
- The URL shown in the error message is the resource you need to fix
Using Online Tools
Tools like "Why No Padlock" (whynopadlock.com) or various SSL Checker websites will scan your page and list all HTTP resources found — far more convenient than checking each page individually in the browser Console. They crawl every resource on the page automatically, which is ideal for sites with many pages where you don't want to open DevTools page by page. The limitation is that these tools can only check pages reachable from the outside (public URLs); back-end pages or anything behind a login won't be scanned.
Another developer favorite is the Security tab in Chrome DevTools, which summarizes whether the page has mixed content, identifies which resource is responsible, and lets you click through to the details. The Network tab also helps you filter http:// requests by inspecting the Scheme or Protocol column.
Fixing Mixed Content Method by Method (DB Search-Replace, Protocol-relative, CSP)
Once you know which resources are still served over http://, it's time for the actual fix. There are several approaches, from fixing the root cause to patching the whole page at once. Pick the one that fits your situation.
Method 1: Search-Replace URLs in the Database (root-cause fix)
If http:// URLs are stored in the database (as with a CMS that keeps content as HTML), fixing the database directly is the most direct route. For a typical MySQL setup you can use an UPDATE statement like this (always back up first):
-- always back up the table first
-- mysqldump -u user -p dbname wp_posts > backup.sql
UPDATE wp_posts
SET post_content = REPLACE(post_content,
'http://yourdomain.com',
'https://yourdomain.com');
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value,
'http://yourdomain.com',
'https://yourdomain.com')
WHERE meta_value LIKE '%http://yourdomain.com%';
A word of caution: if data is stored as serialized values (such as certain options or widgets in WordPress), a raw REPLACE will corrupt the length counters inside the serialized string and break the data. Use a tool that handles serialized data correctly — like WP-CLI or a dedicated plugin — rather than running raw SQL against those fields.
# WP-CLI: safe with serialized data
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' \
--all-tables --dry-run
# review the result, then run for real (drop --dry-run)
wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' \
--all-tables
Method 2: Protocol-relative URLs (//)
If you control the template code, you can change URLs to be protocol-relative by dropping http: and leaving just //. The browser will then pick the protocol matching the current page automatically — if the page is HTTPS, the resource loads over HTTPS too:
<!-- before: always forces http -->
<script src="http://cdn.example.com/lib.js"></script>
<!-- after: protocol-relative, follows the page -->
<script src="//cdn.example.com/lib.js"></script>
<!-- best: specify https explicitly -->
<script src="https://cdn.example.com/lib.js"></script>
Note: today it's recommended to specify https:// explicitly rather than use //, because nearly all sites are HTTPS now, and protocol-relative URLs can break when opening an HTML file locally (where the protocol is file://).
Method 3: CSP upgrade-insecure-requests (whole-page fix)
If http:// resources are scattered across many places and fixing them one by one is impractical, you can tell the browser to "upgrade" every request from http to https automatically using the Content Security Policy directive upgrade-insecure-requests. It can be set in a meta tag or an HTTP response header:
<!-- place in the <head> of every page -->
<meta http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests">
# or as a header in .htaccess (Apache)
Header always set Content-Security-Policy "upgrade-insecure-requests"
# Nginx
add_header Content-Security-Policy "upgrade-insecure-requests";
This directive forces every same-origin resource specified as http:// to load over https instead — a fast, safe way to plug the problem. But treat it as a helper, not an excuse to skip fixing source URLs, because if a resource genuinely has no HTTPS version, it still won't load.
How to Fix Mixed Content in WordPress
Method 1: Really Simple SSL Plugin
This plugin is the easiest fix for WordPress users. Install and activate it with one click. The plugin will:
- Automatically change WordPress Address and Site Address to HTTPS
- Add a Force HTTPS redirect to .htaccess
- Fix mixed content using a Content Security Policy header with the
upgrade-insecure-requestsdirective
Method 2: Update WordPress URLs to HTTPS
- Go to WordPress Admin → Settings → General
- Change both WordPress Address (URL) and Site Address (URL) from http:// to https://
- Click Save Changes
Method 3: Search and Replace in the Database
Use the Better Search Replace plugin to find and replace http://yourdomain.com with https://yourdomain.com across the entire database. This addresses the root cause. Always back up before proceeding:
- Install and activate Better Search Replace
- Go to Tools → Better Search Replace
- Enter
http://yourdomain.comin the Search for field - Enter
https://yourdomain.comin the Replace with field - Select all database tables
- Run a Dry Run first to preview changes, then run the actual replacement
Method 4: Really Simple SSL Together with Better Search Replace
For WordPress, combining these two plugins is the most thorough recipe. Start with Really Simple SSL to force HTTPS, set up redirects, and enable upgrade-insecure-requests automatically. The plugin also includes a built-in mixed content scanner and warns you if there are resources it can't resolve. Then use Better Search Replace to sweep out http:// URLs buried deep in the database — it handles serialized data safely, unlike running raw SQL yourself.
The recommended order is: back up the database → run Better Search Replace as a Dry Run to see how many entries will change → run it for real → enable Really Simple SSL to handle headers and redirects → clear caches (both plugin cache and CDN) → reopen the DevTools Console to confirm no mixed content remains. Clearing the cache is critical, because pages cached before the fix may still contain http:// URLs, leading you to think the fix didn't work.
Fixing Mixed Content in Non-WordPress Sites
Search through all your HTML, CSS, and JavaScript code for URLs beginning with http:// and change them to https://. Alternatively, use protocol-relative URLs in the format //example.com/resource, which automatically inherit the page's current protocol without explicitly specifying http or https. Beyond HTML files, don't forget URLs embedded in CSS — especially url() in background-image and @import — as well as URLs that JavaScript builds dynamically, such as concatenated API endpoint strings, which are often overlooked because they don't appear directly in the HTML.
If you use a build system (such as Webpack or Vite), check any config that sets the base URL or public path to ensure it's https or relative, not a hardcoded http value. And if your site sits behind a reverse proxy or load balancer doing SSL termination, set the X-Forwarded-Proto header correctly so the application knows the request arrived over https and generates internal links as https accordingly.
CDN and Third-Party Resources
External services like Google Fonts, jQuery CDN, Facebook SDK, and chat widgets almost all support HTTPS now. Verify that any embed codes or CDN URLs you use in your site start with https:// rather than http://. If a third-party service does not support HTTPS, consider switching to an equivalent that does.
Frequently Asked Questions About Mixed Content
Why does my site still show "Not Secure" after installing SSL?
Because SSL makes the page's "main connection" HTTPS, but if the page still loads resources (images, scripts, CSS) over http://, the browser treats the whole page as not fully secure and removes the padlock. This isn't a problem with the SSL certificate itself — it's the resource URLs inside the page. Once every URL is changed to https, the padlock returns on its own.
Does mixed content affect SEO and Google rankings?
It has an indirect effect. Google treats HTTPS as a ranking factor, and a "Not Secure" warning raises bounce rates, which is a negative signal. In addition, blocked active mixed content can break analytics scripts or key features, hurting the user experience. Fixing it all is good for both security and SEO.
I fixed mixed content but some pages still warn. Why?
The most common cause is caching — browser cache, plugin cache, and CDN cache. Pages cached before the fix still contain http:// URLs. Clear every cache layer and retest in Incognito mode. Another cause is resources created dynamically by JavaScript or embedded in CSS, which a database search-replace may have missed.
Can upgrade-insecure-requests replace fixing the URLs entirely?
It can serve as a helper, but you shouldn't rely on it alone. The directive does upgrade http requests to https automatically, but if a source resource has no HTTPS version, it still won't load. The best approach is to fix the source URLs correctly and use upgrade-insecure-requests as an extra safety net.
Need an SSL Certificate for Your Website?
Paid SSL from 1,000 THB/year, or free Let's Encrypt included with AsiaGB Hosting.
View SSL Certificates