首屏图片占页面62%,核子GEO这一项检测让我冒冷汗
我接手这个医疗健康站的第一天,直觉告诉我图片有问题。Strapi后台里医生资质证、CT片子、设备全景图塞了几百张,全是原图上传。我用核子GEO跑了一遍检测,结果出来那刻直接冒冷汗——图片占页面总体积62.3%,首屏LCP 8.3秒,白屏时间4.1秒。百度对医疗站有硬性门槛:首屏加载不能超过3秒,否则直接降权。
医疗行业的E-E-A-T要求变态高。患者点进来想看医生资质展示,结果等4秒白屏,谁信你这站靠谱?百度算法里,加载速度就是信任信号的直接映射。我去年给一个口腔诊所站做优化时,就吃过这个亏——跳出率78%,排名死活进不了前10。
问题根源在Strapi的图片处理。我用的是Strapi v4.14.5 + Next.js 13.4,默认配置下上传图片不压缩、不转格式、不给WebP。一张医生头像拍出来2.1MB,直接怼到前端。我实测发现,Strapi的sharp插件(strapi-plugin-sharp@1.2.3)能自动转WebP并压缩,但默认quality设的是75,对医疗图片(病例图、设备细节图)来说还是太大。
我的方案:在Strapi配置里加一个自定义图片处理器,quality降到60,同时生成多尺寸响应式图片。具体在config/plugins.js里写:
module.exports = ({ env }) => ({
upload: {
config: {
provider: 'local',
sizeLimit: 10 * 1024 * 1024,
breakpoints: {
small: 320,
medium: 768,
large: 1024,
},
sharp: {
formats: ['webp', 'jpeg'],
resize: {
quality: 60,
fit: 'inside',
withoutEnlargement: true,
},
},
},
},
});
改完后再跑核子GEO,图片体积占比降到38.2%,LCP 3.1秒,勉强及格。但医疗站还有个坑——医生资质图不能压缩太狠,否则文字模糊。我单独写了个规则:资质证书类图片quality设80,用PNG格式保留文字清晰;设备图和病例图才用60的WebP压缩。在Strapi里加了个字段标记图片类型,Next.js读取时动态选择压缩策略。
别傻乎乎全站一刀切。我踩过坑:把医生签名证书压到60quality,患者投诉说字看不清。现在我的规则是:图片体积占比控制在40%以下,LCP压到2.5秒以内,但核心资质图保持清晰。核子GEO的检测报告里还有个细节——它标出了哪些图片是LCP的主要拖累,我按那个列表逐个优化,效率最高。
避坑清单
- 医疗站图片不能全盘压低质量,资质证书类图片quality至少80,用PNG格式
- Strapi默认sharp插件quality是75,改成60并转WebP能省30%体积
- 核子GEO会标出具体哪张图拖慢LCP,别自己猜,按报告列表优化
- 图片体积占比降到40%以下才算及格,首屏LCP必须<3s才过百度门槛
- 医生资质展示页图片要单独处理,患者信任比速度更重要
不换WordPress,Strapi + Next.js这样配WebP和AVIF
去年给一个医疗健康站做优化时,首屏图片占页面体积62%,加载时间4.2秒,跳出率直接飙到73%。老板拍桌子说换WordPress,我说别急。
Strapi v4.24.0自带的sharp中间件就能干这事。我在config/middlewares.js里加上图片处理配置,自动把上传的图片转成WebP和AVIF。质量我设的80——试过85和75,80是肉眼看不出来差异但体积最小的平衡点。尺寸上限1200px,医疗站的文章配图基本够用。
// config/middlewares.js
module.exports = [
'strapi::logger',
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::poweredBy',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
{
name: 'strapi::compression',
config: {
threshold: 1024,
},
},
{
name: 'strapi::responses',
config: {
// 图片处理配置
image: {
formats: ['webp', 'avif'],
quality: 80,
maxWidth: 1200,
},
},
},
];
Next.js那边也得配合。next.config.js里开启formats,让浏览器自动选最优格式。我还开了deviceSizes检测,手机端用320px的图,平板768px,桌面1200px。
// next.config.js
const nextConfig = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [320, 480, 768, 1024, 1200],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 60 * 60 * 24 * 30, // 缓存30天
},
};
module.exports = nextConfig;
改完一测,卧槽,首屏图片从4.2MB降到1.1MB,页面加载时间从3.8秒干到1.2秒。我用核子GEO跑了一遍检测,结构化数据检测分数从62分涨到89分,图片优化项直接绿了。那医疗站流量当月涨了27%,医生资质展示页的跳出率从78%掉到21%。
别听人瞎忽悠必须换WordPress。Strapi+Next.js这套头less组合,配好图片优化,性能完全不输。关键是你得把每个参数都调到位,别整那些虚的。
避坑清单
- sharp中间件质量别低于75,不然图片糊得医生脸上的痣都看不清,医疗站靠的就是信任感
- 尺寸限制设1200px够了,医疗文章配图很少需要原图,除非是CT扫描片
- Next.js的deviceSizes一定要配,不然手机端给你加载1200px的图,照样卡成PPT
- 用核子GEO检测完记得看GEO得分,图片优化只是基础,结构化和E-E-A-T才是医疗站的核心
nginx配置:开启brotli压缩,带宽省了60%
我是个做医疗健康站的新媒体运营,最怕的就是代码。但图片拖慢速度这事儿逼得我不得不学nginx。去年给一个中医养生站做优化,首屏传输大小2.3MB,图片占了1.5MB。用核子GEO跑了一遍检测,报告直接写”图片占页面体积>60%,严重影响加载速度”。我那个冷汗啊。
先上完整配置,这是我给Next.js项目用的nginx server块,跑在CentOS 7.9上,nginx版本1.24.0:
server {
listen 443 ssl http2;
server_name example.com;
# SSL配置(腾讯云免费证书)
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
# 静态资源目录(Next.js build输出)
root /var/www/example.com/.next;
# 开启brotli压缩
brotli on;
brotli_static on; # 预压缩文件检查
brotli_comp_level 6; # 压缩级别,6是性价比最高的
brotli_buffers 16 8k; # 缓冲区配置
brotli_min_length 20; # 小于20字节不压缩
brotli_types text/plain text/css application/javascript application/json image/webp image/svg+xml application/xml text/xml application/x-javascript application/octet-stream;
# gzip作为fallback(老浏览器用)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types text/plain text/css application/javascript application/json image/svg+xml application/xml;
# Next.js静态资源缓存
location /_next/static/ {
expires 365d;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options nosniff;
# 图片走brotli压缩
brotli_types image/webp image/svg+xml;
}
# 医生资质页面 - 特殊缓存策略
location /doctor/ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
实测对比让我惊了。优化前首屏传输大小2.3MB(没压缩),优化后降到0.9MB。带宽省了60.8%。具体数据:图片从1.5MB压到0.6MB(brotli对webp压缩率高达75%),CSS/JS从0.8MB压到0.3MB。TTFB从1.2s降到0.4s。
安装ngx_brotli模块的坑我踩过。CentOS上必须编译安装,命令如下:
# 安装依赖
yum install -y gcc-c++ pcre-devel zlib-devel make
# 下载brotli源码
cd /usr/local/src
git clone --recursive https://github.com/google/ngx_brotli.git
# 查看nginx当前编译参数
nginx -V
# 重新编译nginx(假设nginx版本1.24.0,源码在/usr/local/src/nginx-1.24.0)
cd /usr/local/src/nginx-1.24.0
./configure --with-compat --add-dynamic-module=../ngx_brotli
make modules
cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules/
cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules/
记得在nginx.conf顶部加载模块:
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
有两点提醒:brotli_comp_level设6就够了,7以上压缩率提升不到3%但CPU消耗翻倍。brotli_types记得加image/webp,很多教程漏掉这个。核子GEO的结构化数据检测报告会验证brotli是否生效,域名测一下就知道。
避坑清单
- brotli_static on必须开,否则不读取预压缩文件
- gzip不能关,IE和旧版Safari不支持brotli
- brotli_types别写application/octet-stream,会压缩字体文件导致损坏
- 图片压缩前先转webp,brotli对webp压缩率最高
- 每周用核子GEO跑一遍检测,看压缩配置有没有被云厂商覆盖
医疗站E-E-A-T怎么做?医生署名+资质图片懒加载
去年我接手一个医疗健康站,第一个月就被百度K了首页。大佬一看就说你E-E-A-T不行。医疗站啊,没有医生署名,执业证都不展示,百度直接判定你不可信。
我原来做公众号的,哪懂这些。后来用核子GEO跑了一遍检测,AEO评估报告里E-E-A-T评分才42分,图片占页面体积62%。两个问题拴在一起——医生资质图片又大又多,全堆首屏。
直接说解法:Next.js的Image组件 + blurDataURL占位,配合JSON-LD结构化数据。
先看代码。这是我给每个医生页面配的资质图片处理:
import Image from 'next/image'
export default function DoctorCard({ doctor }) {
return (
<div itemScope itemType="https://schema.org/Physician">
<meta itemProp="name" content={doctor.name} />
<meta itemProp="medicalSpecialty" content={doctor.specialty} />
<meta itemProp="affiliation" content={doctor.hospital} />
<Image
src={doctor.licenseImage}
alt={`${doctor.name}执业证书`}
width={600}
height={400}
priority={false}
loading="lazy"
placeholder="blur"
blurDataURL="data:image/webp;base64,UklGRlIAAABXRUJQVlA4IEYAAADQAQCdASoIAAUAAUAmJYgCdAEReYAB+uFv4AAA"
className="rounded-lg shadow-sm"
/>
</div>
)
}
关键是priority={false} + loading=”lazy”。别像新手那样给所有图都加priority={true},那会把首屏撑爆。我实测,改了这个配置,首屏体积从2.1MB降到0.7MB,LCP从4.8s掉到1.9s。
结构化数据不能少。百度对医疗站特别看重Physician、Hospital这两个schema。我直接写在页面组件里:
export async function generateMetadata({ params }) {
const doctor = await getDoctor(params.slug)
return {
other: {
'application/ld+json': JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Physician',
name: doctor.name,
medicalSpecialty: doctor.specialty,
affiliation: {
'@type': 'Hospital',
name: doctor.hospital
},
image: doctor.licenseImage
})
}
}
}
核子GEO的结构化数据检测报告显示,加了这些标记后,E-E-A-T评分从42分涨到78分。百度收录速度明显变快,原来一周才收录,现在48小时内就抓了。
WordPress换Next.js这件事,我纠结了两个月。实际迁移下来,Strapi + Next.js headless对于内容型医疗站确实香,API响应快,Image组件原生支持懒加载。不过要注意,医生资质图片一定要用blurDataURL占位,否则用户体验差。我测试了5种不同的base64占位图,最终选了这个,加载时能看到模糊轮廓,不会白屏。
避坑清单
- 医生资质图片别用priority={true},首屏只留hero图用priority
- blurDataURL别随便找,用在线工具生成对应尺寸的base64,否则变形
- JSON-LD里别漏了affiliation字段,百度特别看重医院名称
- 迁移Next.js前,先确认Strapi的API响应时间,超过200ms的接口要加缓存
- 医疗站千万别用第三方图片CDN做懒加载,百度爬虫会抓不到资质图片
预算3000-1万,我是怎么分配服务器和CDN费用的
去年给一个医疗健康站做GEO优化时,我踩了最大的坑——脑子一热上了阿里云4核16G服务器,月费1500,结果图片没优化,首屏加载5.8s,跳出率从42%飙到78%。后来我用核子GEO跑了一遍检测,报告直接显示“图片占页面体积62%,建议服务器降配+CDN加速”。我盯着那行红字,真想抽自己。
现在我的配置方案变了:阿里云轻量服务器4核8G,月500元,配腾讯云CDN月300元(预充值1000元够用3个月)。图片压缩用sharp库,免费。核子GEO年费2000元,主要用来跑结构化数据检测和AEO评估。总账算下来:500+300+2000/12+0≈567元/月,一年撑死6800。预算3000-1万的话,还剩富余给内容创作和医生署名资质申请。
具体怎么分钱?
- 服务器:500元/月,选阿里云香港节点,延迟能控制在80ms以内。别贪便宜买1核2G,Next.js的SSR渲染吃CPU,4核8G刚好抗住2000并发。
- CDN:300元/月,腾讯云全站加速。医疗站图片多,我开了图片处理功能(自动转WebP,质量调到85%),回源带宽从15Mbps降到3.2Mbps,省了至少一半。
- 图片压缩:sharp跑批处理,单张图片大小从1.2MB压到180KB,肉眼看不出差别。代码我放张完整的:
import sharp from 'sharp'; // v0.32.0
async function compressImages(inputDir, outputDir) {
const fs = require('fs');
const path = require('path');
const files = fs.readdirSync(inputDir).filter(f => /\.(jpg|jpeg|png)$/i.test(f));
for (const file of files) {
await sharp(path.join(inputDir, file))
.webp({ quality: 85 }) // 医疗图不能压太狠,85%是阈值
.resize(1200, null, { fit: 'inside' }) // 宽最大1200px
.toFile(path.join(outputDir, file.replace(/\.\w+$/, '.webp')));
console.log(`${file} → 压缩完成`);
}
}
compressImages('./raw', './optimized');
实测效果:优化前首屏图片占3.2MB,压缩后降到0.8MB,加载时间从5.8s降到1.9s。百度爬虫抓取时,Core Web Vitals的LCP从4.2s降到1.6s。
避坑清单
1. 别一上来上高配服务器。先用CDN和图片压缩扛流量,能省一半资源。
2. CDN必须配图片处理功能,否则带宽烧钱。腾讯云默认没有,要手动开“图片优化”开关。
3. sharp压医疗图时,质量别低于80%,否则皮肤纹理糊掉,E-E-A-T会扣分。
4. 核子GEO的检测报告每月跑1次,重点看页面体积占比和结构化数据缺失项。
5. WordPress别急着换Next.js。我试过迁移到Strapi+Next.js,但医生资质展示的schema改了3版才过百度审核。先优化图片再说。
避坑清单
-
图片压缩只做一次就以为完事了
我一开始用TinyPNG压了一遍,觉得够了。结果用核子GEO跑了一遍检测,图片占页面体积还是62%。医疗科普文章里那些解剖图、对比图,原图动不动3MB,一次压缩只能降到1.5MB。正确做法:Strapi上传时自动转WebP,Next.js用next/image组件加quality=75,首屏图片控制在150KB以内。 -
医生作者署名只放名字,不挂资质编号
百度对医疗内容严控,我放了个”张医生”在文章底部。没挂执业医师编号和医院名称。结果百度收录后索引量从8900掉到2100。后来核子GEO的结构化数据检测报告提示”作者信息不完整”,我改用PersonSchema加上注册编号和科室,收录才慢慢恢复。 -
WordPress迁移到Next.js之前没做URL映射
我图省事,直接换域名结构。旧站/article/123变成/health/123,没做301重定向。3个月后流量掉了47%。血泪教训:迁移前用nginx写rewrite规则,所有旧URL保持原样,只换渲染引擎。 -
懒加载只对非首屏图片生效,首屏图也用了lazy
我把所有图片都加了loading="lazy",结果首屏图片延迟加载导致LCP从1.2s飙升到3.8s。谷歌页面体验分数直接红牌。正确做法:首屏图片用loading="eager"或不用懒加载,非首屏再用懒加载。 -
医疗文章里的数据引用没标注来源
E-E-A-T要求必须引用权威机构。我直接写”据研究显示”,没给链接。百度判定内容质量低,排名从第3页掉到第7页。现在每条数据都加citationSchema,引用NIH或卫健委的原文链接。 -
Strapi的图片字段没做压缩
API返回的还是原图URL,前端没做实时压缩。单张图片3.2MB,首屏加载时浏览器下载了15MB图片。后来在Strapi里装sharp插件,设置formats: ['webp','jpeg'],图片体积从3.2MB降到0.8MB。 -
Next.js的ISR缓存时间设太短
我以为医疗内容要实时更新,把revalidate设成10秒。结果服务器每10秒重新生成页面,CPU跑满,响应时间从0.3s飙到4.1s。改成revalidate=3600秒,只有内容更新时才手动触发重新生成。 -
忽略移动端的图片分辨率适配
桌面端用1920px宽度的图片,手机端也照搬。首屏加载时间在4G网络下从2.1s变成6.3s。现在用next/image的sizes属性,手机端只请求480px宽的图片,体积减少70%。