业务需要对项目进行seo搜索优化,seo有很多中的内容,这次也是分为了多期开发, 第一次主要从下面几个方面进行调整:
- URL优化
- 页面的meta标签和关键词的优化
- 301重定向
还有其他的内容, 比如增加页面的内容 丰富性也能提升排名。
学无止境,但是头发有。
一、URL优化
网站搭建的初期没有考虑到seo优化这个方向,所以在路由设计上有很多问题,路由的调整是非常大的(如果要做seo建议一开始就做好后续的迭代坑位)
产品是某招聘软件,可以根据地址和招聘类型进行查询,之前是按照我们的业务模块进行的地址定义,这样不能准确的的被爬取到,因此,路由改变和地址转义是第一步。
文件目录的改变,因为next的特性,目录就是路由,所以第一步就是要改目录名称
这样在浏览器上访问的时候就是最新, 我们是招聘软件,因此命名是跟招聘有关的,其他行业可以使用其他的命名。
我们可以通过这样的地址去访问到对应的页面
第二个是参数的问题,我们采用城市+类型的形式去拼接我们的地址,因为我们的筛选参数是从地址获取的。
举个栗子,这样的地址代码我们是在找成都区域的程序员工作,这就是我们的最终的url类型格式
1、地址转义
地区肯定是以行政编码为准,因此我们需要维护一个地址库
里面有拼音、中文和行政编码的对照关系,因为后面的meta需要使用到中文,所以需要有这个中文的对照,至于需不需要很详细看业务需求。
用户看到的是拼音地址,meta标签中用的是中文,后面会说,传递给后端的是行政码。
还需要一些配套的方法来拿到对应的拼音或者行政码:
当然这个看自己设计,精细一点可以把方法封装深一点,根据不同参数取不一样的数据
通过这些方法我们可以拿到地址的信息,便于后面的meta标签和jsonLd数据等的拼接。
至于后面的参数拼接,则根据自己的实际需求来做就行了,这里就不说了。
举例:
首页:https://www.xxx.cn/【城市拼音】——其他信息
// 列表
https://www.xxx.cn/xx1/chengdu_chengxuyuan
规则:https://www.xxx.cn/xx1/【城市名字拼音】_【其他的参数信息】
// 详情 我们是地址栏拼接了参数的,根据自己的需求来
规则:https://xxx.cn/xxxx1/[id/标识/或者其他信息].html?type=xx&code=123
地址转移,自己其他地方取参数也是一致的,定义自己的规则就行了。
2、301优化
301优化,我们没有www 域名,所以需要做一个域名转发,
文档中也有写:nextjs.org/docs/app/ap…
就是再next.config.js 中新加一个配置项。但是具体规则还是要根据自己的网站需求来
xxx.cn/22333/ 到 www.xxx.cn/chengdu/
// // 301优化
async redirects() {
return [
{
source: '/:path*',
has: [
{
type: 'host',
value: 'xxx.cn',
},
],
destination: 'https://www.xxx.cn/:path*',
permanent: true,
},
];
},
二、页面Meta标签
页面meta标签是必须的,可以简单也可以难一点,根据自己需求来就好了。
我们采用的next.js实现的,所以自己写再html肯定不显示
还是根据文档来:nextjs.org/docs/app/bu…
官网提供两个,一个是静态,就是不需要加入参数,直接放在我们的组件前面就好了,
是放在服务端组件哦,不要放在客户端去了。
1、静态meta
内容是写死的,基本没啥配置的能力
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: '解签下江南',
description: 'SEOmeta讲解',
keywords:"关键词"
}
export default function Page() {}
最终再浏览器渲染出来:
有很多中的meta标签,按照自己的需求配置就行。
如果是ts的话们可以从 Metadata 类型点击进去,就可以看到支持的类型 。
<title>解签下江南</title>
<meta name="description" content="SEOmeta讲解" />
<meta name="keywords" content="关键词" />
2、动态meta
顾名思义,里面的数据可以变化,根据url的不同或者其他内容去切换和更改meta显示的
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export async function generateMetadata(
{ params, searchParams }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// read route params
// 这里拿到的就是我们的路由参数
const id = (await params).id
// fetch data
// 如果有一些数据需要根据后台请求去或者再这里可以定义
const product = await fetch(`https://.../${id}`).then((res) => res.json())
// optionally access and extend (rather than replace) parent metadata
// 这个就是一些图片数据
const previousImages = (await parent).openGraph?.images || []
return {
title: product.title,
openGraph: {
images: ['/some-specific-page-image.jpg', ...previousImages],
},
}
}
export default function Page({ params, searchParams }: Props) {}
看了上面的例子相信你也看出了一些,异步其实最终还是返回一个meta对象,只不过他的对象内容可以自己去组装,根据路由参数,或者请求的数据去切换,针对不同的页面可以修改成对应的针对信息。
我们的项目做了抽取
type Props = {
params: Promise<{ code: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
// const code = (await params).code;
const code = await params;
return getHeadMeta(code, META_TYPE)! as Metadata;
}
方法内部实现:
export const getHeadMeta = (
param: Record<string, string>,
type: META_TYPE,
searchParam: { [key: string]: string | string[] | undefined } = {},
) => {
// 根据传入的参数,返回对应类型的headmata标签
let titleContent = "解签下江南";
let descriptionContent = "seo";
let keywordsContent = "关键内容";
switch (type) {
case META_TYPE.x: //首页
return {
title: "解签下江南",
description:"解签下江南",
other: {
"applicable-device": "pc",
renderer: "webkit",
},
...COMMON_META_SCRIPT,
alternates: {
canonical: `https://www.xxx.cn/${param.code || ""}`,
},
};
case META_TYPE.xx1: //特殊页面根据页面信息进行一些内容切换
const Address = param.code.split("_")[0];
const { name }: AddressData =
getAddressData(zhaopinAddress)!;
titleContent = `${name}解签下江南`;
descriptionContent = `${name}seo`;
keywordsContent = `${name}解签下江南`;
return {
title: titleContent,
description: descriptionContent,
keywords: keywordsContent,
other: {
"applicable-device": "pc",
renderer: "webkit",
},
...COMMON_META_SCRIPT,
alternates: {
canonical: `https://www.xxxx.cn/xxx1/${param.code}`,
},
};
。。。。。
// 官网下载页等。。。。
case META_TYPE.OTHER_PAGE: //
return {
title: "解签下江南",
description:"解签下江南",
};
default://兜底选择
return {
title: "解签下江南",
description:"解签下江南",
other: {
"applicable-device": "pc",
renderer: "webkit",
},,
};
}
};
http-equiv 属性内容写在head中
再head中添加script标签
因为直接这样使用会被检测出语法错误
<script type="application/ld+json">
{
"@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld",
"@id": "https://www.xxx.cn/",
"title": "解签下江南",
"description": "解签下江南"
}
</script>
需要转义一下,用模板字符串多重包裹
<script type="application/ld+json">
{`{ "@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld",
"@id": "https://www.xxx.cn/",
"title": "解签下江南!",
"description": "解签下江南"
}`}
</script>
根据不同的参数去判断该使用那些meta,例如官网就该是 xxx官网, 如果是网站就可以放一些 啥网站之类的描述
这样就达到了我们的动态meta的要求
3、JSON-LD
很多网站都有生成一个jsonld的sciprt标签
boss
小米官网:
里面也是放一些信息标签
这个内容也是再服务端组件,放在,我们的组件代码中,最终生成是再html的head里面
我们也是做了抽取的,因为next的机制问题,每个页面都要用一下
const jsonLd = getJsonLd(META_TYPE, paramData);
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div> xxx内容</div>
<>
)
方法内部:
// 返回一个jsonLd对象
export const getJsonLd = (
type: META_TYPE,
param: Record<string, string | number | undefined>,
) => {
switch (type) {
case META_TYPE.HOME_PAGE:
const address = getAddressRegionName(param.region as string);
const metaContent = {
title: "解签下江南",
description:"解签下江南",
};
return {
"@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld",//百度的链接
"@id": `https://www.xxx.cn/${addressPronunciation}`,
title: `${metaContent.title}`,
description: `${metaContent.description}`,
};
其他的类型跟meta一致。
。。。
// 默认
default:
return {
"@context": "https://ziyuan.baidu.com/contexts/cambrian.jsonld",//百度的链接
"@id": `https://www.xxx.cn/${addressPronunciation}`,
title: `${metaContent.title}`,
description: `${metaContent.description}`,
};
break;
}
};
这样我们就可以添加了,这个看需求,需要就加,不需要就不加。
4、next提供的Script标签
这里再开始的时候没注意看文档,直接搜的script,出来了这个标签
最开始就以为这个可以实现jsonld。
试了一下发现,这样生成的script标签是在body中的,使用角度不一样。
使用用法你们自己去摸索吧。
三、百度代码和robots
1、robots
next是再public中加一个就行。
内容看个人需求:
User-agent: *
Allow: /xx1/
Allow: /xx2/
Disallow: /*?*
注意的是,next会自动生成这个文件
因此,如果要个性化的话就要关闭自动生成配置
next-sitemap.config.js 文件中的 generateRobotsTxt 配置要确保是false
不然就会自己生成,导致我们加的不生效。
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: "https://xx1.cn",
generateRobotsTxt: false, // 关闭配置!!!!
exclude: ["/test"]
};
2、百度代码
最外层的layout文件中,需要添加这一段,自己去百度的监控平台注册,把自己的网站上传上去就行。
这样百度才能爬去到
四、页面内链优化
所有可以点的的链接都用a标签包起来,next提供组件,link组件就是a标签封装的,所以可以直接使用a标签的属性
本次分享就到此为止,我也是初入,以后有机会继续更新。
=========== =========== =========== ===========