如何删除文章网址末尾的斜杠

时间:2021-06-24 10:21:36

标签: javascript node.js reactjs gatsby gatsby-image

我刚刚开始学习 Gatsby,我刚刚从 gatsby 模板导入了一个 gatsby 项目。我的 og:image 显示不同的 Open graph 标签有问题,我想显示文章的缩略图。

例如这篇文章 - https://www.armanism.com/blog/install-nginx-on-ubuntu 当我尝试从 Twitter 卡验证器获取数据时,它显示重定向到“https://www.armanism.com/blog/install-nginx-on-ubuntu”到“https://www.armanism.com/博客/install-nginx-on-ubuntu/"

Check this screenshot

有人可以帮我解决这个问题吗?

这是我的 gatsby SEO 配置

/* Vendor imports */
import React from 'react';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import { StaticQuery, graphql } from 'gatsby';
/* App imports */
import Config from '../../../config';
import Utils from '../../utils/pageUtils';

const detailsQuery = graphql`
  query DefaultSEOQuery {
    file(name: { eq: "facebook-icon" }) {
      childImageSharp {
        fixed(width: 600) {
          ...GatsbyImageSharpFixed_noBase64
        }
      }
    }
  }
`;

function SEO({
  title,
  description,
  path,
  lang,
  keywords,
  contentType,
  imageUrl,
  translations,
  meta,
}) {
  return (
    <StaticQuery
      query={detailsQuery}
      render={(data) => {
        const metaKeywords = keywords && keywords.length > 0
          ? { name: 'keywords', content: keywords.join(', ') }
          : [];
        const pageUrl = Utils.resolvePageUrl(
          Config.siteUrl,
          Config.pathPrefix,
          path,
        );
        const fixpageUrl = pageUrl.replace('/https://', 'https://');
        const metaImageUrl = Utils.resolveUrl(
          Config.siteUrl,
          imageUrl || data.file.childImageSharp.fixed.src,
        );
        const fixmetaImageUrl = metaImageUrl.replace('/https://', 'https://');
        return (
          <Helmet
            title={title} // Page title
            titleTemplate={`%s – ${Config.siteTitle}`}
            meta={
              [
                { name: 'description', content: `${description.substring(0, 160)}...` }, // Page description
                /* Open Graph */
                { property: 'og:title', content: title },
                { property: 'og:type', content: contentType || 'website' },
                { property: 'og:url', content: fixpageUrl },
                { property: 'og:description', content: `${description.substring(0, 160)}...` },
                { property: 'og:image', content: fixmetaImageUrl },
                { property: 'og:image:alt', content: title },
                { property: 'og:site_name', content: Config.siteTitle },
                { property: 'og:locale', content: lang || 'en_US' },
                /* Twitter card */
                { name: 'twitter:card', content: 'summary_large_image' },
                { name: 'twitter:title', content: title },
                { name: 'twitter:description', content: `${description.substring(0, 160)}...` },
                { name: 'twitter:image', content: fixmetaImageUrl },
                { name: 'twitter:image:alt', content: title },
                { name: 'twitter:site', content: Config.author },
                { name: 'twitter:creator', content: Config.author },
              ]
                .concat(metaKeywords) // Keywords
                .concat(meta || []) // Other provided metadata
            }
            link={[
              { rel: 'canonical', href: fixpageUrl }, // Canonical url
            ]
              // Translated versions of page
              .concat(
                translations
                  ? translations.map((obj) => ({
                    rel: 'alternate',
                    hreflang: obj.hreflang,
                    href: Utils.resolvePageUrl(
                      Config.siteUrl,
                      Config.pathPrefix,
                      obj.path,
                    ),
                  }))
                  : [],
              )}
          />
        );
      }}
    />
  );
}

SEO.propTypes = {
  title: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  path: PropTypes.string.isRequired,
  lang: PropTypes.string,
  contentType: PropTypes.oneOf(['article', 'website']),
  imageUrl: PropTypes.string,
  keywords: PropTypes.arrayOf(PropTypes.string),
  translations: PropTypes.arrayOf(
    PropTypes.shape({
      hreflang: PropTypes.string.isRequired,
      path: PropTypes.string.isRequired,
    }),
  ),
  meta: PropTypes.arrayOf(
    PropTypes.shape({
      property: PropTypes.string.isRequired,
      content: PropTypes.string.isRequired,
    }),
  ),
};

SEO.defaultProps = {
  lang: 'en_US',
  contentType: 'website',
  imageUrl: null,
  keywords: [],
  translations: [],
  meta: [],
};

export default SEO;

这是我的 PageUtils 代码

/* eslint-disable no-param-reassign */
const Config = require('../../config');

const Utils = {
  /**
   * Join provided url paths.
   * @param {...string} paths Provided paths. It doesn't matter if they have trailing slash.
   * @return {string} Resolved url without trailing slash.
   */
  resolveUrl: (...paths) => paths.reduce((resolvedUrl, path) => {
    const urlPath = path.toString().trim();
    if (urlPath) {
      // eslint-disable-next-line no-param-reassign
      resolvedUrl
          += (resolvedUrl === '' ? '' : '/') + urlPath.replace(/^\/|\/$/g, '');
    }

    resolvedUrl = resolvedUrl[0] !== '/' ? `/${resolvedUrl}` : resolvedUrl;
    return resolvedUrl;
  }, ''),
  /**
   * Resolve a page url adding a trailing slash.
   * Needed to prevent 301 redirects cause of Gatsby.js' folder structure.
   * @param {...string} path Provided paths. It doesn't matter if they have trailing slash.
   * @return {string} Resolved url with trailing slash.
   */
  resolvePageUrl: (...path) => {
    const resolvedUrl = Utils.resolveUrl(...path);
    return resolvedUrl;
  },
  /**
   * Get an ordered list of suggested posts for a single post.
   * @param {Object} post The single post of which to find the related posts.
   * It's the returned object from Graphql's query `markdownRemark`
   * @param {Array} postList The list where find related posts. It's the returned
   * object from Graphql's query `allMarkdownRemark`
   * @param {number} limit The maximum number of suggested posts to get
   * @return {Array} The `postList` object sorted according to the best match with the `post` object
   */
  getSuggestedPosts: (post, postList, limit) => {
    // Get the number of common tags with provided post.
    const getTagScore = (edge) => {
      let commonTags = 0;
      edge.node.frontmatter.tags.forEach((tag) => {
        commonTags += post.frontmatter.tags.indexOf(tag) !== -1 ? 1 : 0;
      });
      return commonTags;
    };

    return postList.edges
      .sort((edgeA, edgeB) => getTagScore(edgeB) - getTagScore(edgeA))
      .slice(0, limit);
  },
  /**
   * Pass a post and retrieve a list of related translations.
   * @param {Object} post The post of which retrieve its translations.
   * It accepts a `node` object from Graphql's query `allMarkdownRemark`
   * @param {Object} postList The list of posts where search translations.
   * It accepts a `edges` array from Graphql's query `allMarkdownRemark`
   * @return {Object} An array of objects with languages as keys (ISO 639-1) and
   * translated post's paths as values.
   */
  getRelatedTranslations: (post, postList) => postList
    .filter(({ node }) =>
    // Get posts in the same folder of provided post
      // eslint-disable-next-line implicit-arrow-linebreak
      (
        node.fileAbsolutePath.split('/').slice(-2, -1)[0]
          === post.fileAbsolutePath.split('/').slice(-2, -1)[0]
      ))
    .map(({ node }) => {
      const lang = node.fileAbsolutePath.split('.').slice(-2, -1)[0];
      return {
        hreflang: lang.slice(-5) !== 'index' ? lang : Config.defaultLanguage,
        path: Utils.resolvePageUrl(node.frontmatter.path),
      };
    }),
  /**
   * Capitalize passed string
   * @param {string} str string to capitalize
   * @return {string} string with first letter to uppercase
   */
  capitalize: (str) => str[0].toUpperCase() + str.slice(1),
};

module.exports = Utils;

如果您需要任何其他信息,请告诉我

提前致谢

1 个答案:

答案 0 :(得分:0)

我认为您的问题与您的 SEO 组件或您的项目功能本身无关。我认为您的问题依赖于文章创建 (gatsby-node.js),因为它使用尾部斜杠创建 URL,因此附加到该逻辑的所有配置和参数都会继承它。

检查如何在 path 参数中创建文章:

  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug.replace(/\/$/, ''); // original code: node.fields.slug,
      component: path.resolve(`./src/templates/blog-post.js`),
      context: {
        slug: node.fields.slug.replace(/\/$/, '')
      },
    })
  })

注意:基于 Gatsby's tutorial。调整它以适应您的需求。

替代 replace 函数,您可以使用多种字符串操作函数之一,例如:

(node.fields.slug.charAt(node.fields.slug.length - 1) === '/') ? node.fields.slug.slice(0, -1) : node.fields.slug;

或者:

node.fields.slug.endsWith('/') ? node.fields.slug.slice(0, -1) : node.fields.slug;

此外,您还可以使用 gatsby-plugin-remove-trailing-slashes 插件。