Фреймворк рендеринга на стороне сервера Next.js в действии

React.js
Фреймворк рендеринга на стороне сервера Next.js в действии

Next.js — фреймворк рендеринга на стороне сервера, основанный на стеке технологий React.js.

Я впервые опубликовал статью о самородках.С познавательной точки зрения я подытожил восстановление проекта собственной разработки рендеринга на стороне сервера с использованием Next.js, закрепил свои знания и обсудил технологии со своими коллегами. (Статья постоянно совершенствуется...)

1. Предыстория проекта

Оригинальный проект компании был разработан на основе смеси PHP и jQuery и предложенных требований рефакторинга. Однако стек внутренних технологий был заменен с PHP на микросервисы Java, а стек внешних технологий также был заменен с jQuery на React.js. Поскольку отрасль компании нуждается в онлайн-продвижении, рефакторинг проекта следует считать дружественным к SEO-оптимизации.Я обычно использую стек технологий React.js для фронтенд-разработки, поэтому я нашел Next.js (на основе React) Этот сервер- боковая структура рендеринга.

2. Основные потребности

  • индекс поисковой системы: оптимизирован для SEO, удобен для поиска и сканирования информации о странице.
  • благоустройство маршрута: Маршрутизация должна отображаться по правилам
  • Отображение разных данных в зависимости от разных городов: Необходимо отображать разные данные о городах в соответствии с конкретными городами (IP-позиционирование).
  • ПК-конец/М-конец: Рендеринг шаблонов компонентов различных клиентов в соответствии с оценкой устройства.
  • SEO-информация настраивается: Каждая подстраница вверху страницы (например, домашняя страница, страница о нас, страница с описанием компании) поддерживает SEO-информацию и может быть настроена.
  • Поддержка переключения среды разработки/производства: определить текущую среду на основе командной строки и настроить префикс интерфейса API.
  • Развертывание файла авторизации WeChat: файл авторизации платежей WeChat *.txt файл развернут в корневом каталоге проекта
  • Частичная обработка прокси-запроса Http: Междоменная обработка некоторых интерфейсов (http-proxy-middleware)
  • Аналогично обработке перенаправления: доступ к текущему доменному имени, извлечение данных страницы под разными доменными именами и отображение их под текущим маршрутом.
  • моделирование локальных данных: Попытаюсь использовать способ mock.js / json-server / faker.js [инструмент управления документами API может использовать yapi]
  • Метод развертывания проекта: для проекта существует два метода развертывания, основанные на развертывании Docker и развертывании Node (локальная отладка также будет выполняться с помощью Docker).

3. Принцип Next.js

китайский официальный сайтNext.js — это облегченная среда приложений React, отображаемая на сервере. Понимание рендеринга на стороне сервера: на самом деле, многие люди сталкивались с рендерингом на стороне сервера.Самая традиционная вложенная статическая HTML-страница PHP является разновидностью рендеринга на стороне сервера. PHP рендерит данные, полученные из базы данных, в html через шаблонизатор, и когда фронтенд обращается к указанному маршруту, php отправляет их на указанную фронтендом страницу, которая распознается браузером как файл .html (Content- тип: text/html), браузер анализирует и отображает страницу в соответствии со статическим форматом файла html и отображает ее. При просмотре исходного кода в браузере в тегах есть теги расширенного html и текстовая информация, такая как информация SEO , название/содержание статьи и т. д. Такие страницы могут быть легко просканированы поисковыми системами. Принцип Next.js аналогичен, за исключением того, что серверным языком является Node.Динамические данные на стороне сервера, полученные методом getInitialProps, встраиваются в компонент React, а компонент React отображается в html-странице на сервере. стороны и отправлены на передний план.

4. Ключевые моменты Next.js

Файловая система:

Файловая система Next предусматривает, что каждый файл *.js в папке pages станет маршрутом, автоматически обработанным и отрендеренным.

Создайте новый ./pages/index.js в своем проекте.После запуска проекта вы можете получить доступ к странице через путь localhost:3000/index. Точно так же ./pages/second.js можно получить через localhost:3000/second.

Обслуживание статических файлов:

Такие как изображения, шрифты, инструменты js

Создайте новую папку с именем static в корневом каталоге. Код может импортировать связанные статические ресурсы через /static/Не настраивайте имя статической папки, ее можно назвать только статической, потому что только это имя Next.js будет рассматривать ее как статический ресурс.

export default () => <img src="/static/my-image.png" alt="my image" />

сбор информации:

Здесь Next.js включает рендеринг на стороне сервера. Функция getInitialProps предоставляет хуки жизненного цикла для получения данных.

Создайте компонент React с состоянием, жизненным циклом или исходными данными

import React from 'react'

export default class extends React.Component {
  static async getInitialProps({ req }) {
    const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
    return { userAgent } // 这里绑定userAgent数据到Props,组件里就可以用 this.props.userAgent访问到了
  }

  render() {
    const { userAgent } = this.props // ES6解构赋值 
    return (
      <div>
        Hello World {userAgent}
      </div>
    )
  }
}

==========================================

// 无状态组件定义getInitialProps *这种方式也只能用在pages目录下
const Page = ({ stars }) =>
  <div>
    Next stars: {stars}
  </div>

Page.getInitialProps = async ({ req }) => {
  const res = await fetch('https://api.github.com/repos/zeit/next.js')
  const json = await res.json()
  return { stars: json.stargazers_count }
}

export default Page

Приведенный выше код получает данные через асинхронный метод getInitialProps и привязывает их к свойствам. При отображении службы getInitialProps сериализует данные, как JSON.stringify. При первоначальной загрузке страницы getInitialProps будет загружаться только на стороне сервера. Только при переходе маршрута (переход компонента Link или переход метода API) клиент выполнит getInitialProps.

Сфокусируйся на:getInitialProps не будет работать в дочерних компонентах. Может использоваться только на странице страницПодкомпоненты могут получать данные через страницы в папке pages, а затем Props передают значения в подкомпоненты

Свойства входного объекта getInitialProps следующие::

  • pathname - часть пути URL
  • query - часть запроса URL, преобразованная в объект
  • asPath - фактический путь (включая часть запроса), отображаемый в браузере, типа String
  • req - объект HTTP-запроса (только сервер)
  • res - объект возврата HTTP (только на стороне сервера)
  • jsonPageRes — получить объект ответа данных (доступно только на стороне клиента)
  • err - любые ошибки при рендеринге

Реализация коммутации маршрутизации на стороне клиента с помощью компонентов

Если вам нужно ввести имя пути, запрос или asPath в ваш компонент, вы можете использовать компонент более высокого порядка withRouter

// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href="/about">
      <a>here</a>
    </Link>{' '}
    to read more
  </div>
  
// 高阶组件
import { withRouter } from 'next/router'

const ActiveLink = ({ children, router, href }) => {
  const style = {
    marginRight: 10,
    color: router.pathname === href? 'red' : 'black'
  }

  const handleClick = (e) => {
    e.preventDefault()
    router.push(href)
  }

  return (
    <a href={href} onClick={handleClick} style={style}>
      {children}
    </a>
  )
}

export default withRouter(ActiveLink)

5. Каталог проектов

С этого шага начинается процесс фактического создания проекта и написания кода.Поскольку это проект компании, здесь используются все данные моделирования, но упомянутые выше требования проекта будут реализованы с нуля одно за другим.

Установить

1.首先新建目录 ssr 在ssr目录下执行
cnpm install --save next react react-dom // 需要设置 npm镜像

2.执行完命令后目录下出现文件夹node_module 和文件package.json 
ssr
    -node_modules
    -package.json

package.json 文件内容如下
{
  "dependencies": {
    "next": "^8.1.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  }
}

3.添加脚本到package.json文件. 我们可以在这里自定义npm脚本命令
{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "^8.1.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  }
}

4.在ssr目录下新建文件夹 pages | static | components ... ,然后在pages下新建文件 index.js,文件内容如下

export default () => <div>Welcome to next.js!</div>

最终新目录结构如下 [暂时没提到的文件和目录后续会讲到]
ssr
    -node_modules
    -package.json
    -components
    -static
        -imgs
            -logo.png
        -fonts
            -example.ttf
        -utils
            -index.js
    -pages
        -index.js
        -about.js
    -.gitignore
    -README.md
    -next.config.js
    -server.js

5.运行 npm run dev 命令并打开 http://localhost:3000
  执行npm run start 之前需要先执行 npm run build 不然会报错

Откройте и просмотрите исходный код с помощью инструмента отладки браузера, вы увидите, что элементы div отображаются в корневом контейнере _next.Когда данных много, поисковым системам будет удобно сканировать html-код.

Это лучше понять по сравнению с одностраничным приложением SPA.Приложение SPA имеет только один корневой корневой контейнер для монтирования компонентов. Никакой другой расширенный HTML-код не будет виден в контейнере.

6. Реализация требований проекта

Проект предназначен для облегчения рендеринга на стороне сервера для SEO.Когда дело доходит до SEO, вам необходимо установить информацию заголовка заголовка в html-документе. Здесь есть три очень важных фрагмента информации: ключевые слова | описание | заголовок соответственно представляют ключевое слово, описание и заголовок текущей веб-страницы. Поисковая система будет сканировать ключевую информацию веб-страницы в соответствии с содержанием этих тегов, а затем пользователь отобразит страницу результатов поиска в соответствии со степенью соответствия этих ключевых слов при поиске. (Конечно, алгоритм представления — это гораздо больше, чем обращение к этой информации, семантике тегов страниц, плотности ключевых слов, внешним ссылкам, внутренним ссылкам, трафику, времени удержания пользователя...)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="keywords" content="Winyh | Next.js | React.js | Node.js | ...">
    <meta name="description" content="这是一个跟next.js服务端相关的页面">
    <title>基于React.js 技术栈的服务端渲染框架Next.js 实战记录</title>
</head>
<body>
    
</body>
</html>

Требование 1: SEO-информация может быть настроена

Это достигается, и поиск в поисковой системе также является простой реализацией. Чтобы добиться удобства для поисковых систем, на самом деле есть много аспектов, которые можно оптимизировать.

  • Настройте встроенный компонент для загрузки на страницу, назовите файл HeadSeo.js.
// components/Common/HeadSeo.js 文件里代码如下
import Head from 'next/head'

export default () =>
    <Head>
        <meta charSet="UTF-8"> // 注意这里的charSet大写,不然React jsx语法 会报错
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="keywords" content="Winyh | Next.js | React.js | Node.js | ...">
        <meta name="description" content="这是一个跟next.js服务端相关的页面">
        <title>基于React.js 技术栈的服务端渲染框架Next.js 实战记录</title>
    </Head>
    
    
// pages/index.js 文件里代码如下
import Layout from "../components/Layouts/PcLayout"

export default () => 
    <Layout>
        <div>Welcome to next.js!</div>
    </Layout>

相应目录结构为
ssr
    -node_modules
    -package.json
    -components
        -Common   // 公共组件
            -HeadSeo.js
        -Layouts  // 布局文件
            -PcLayout.js
            -MLayout.js
    -static // 静态资源
        -imgs
            -logo.png
        -fonts
            -example.ttf
        -utils
            -index.js
    -pages 
        -index.js
        -about.js
    -.gitignore
    -README.md
    -next.config.js // 配置文件
    -server.js // 服务端脚本

Откройте localhost:3000, и вы увидите, что соответствующая SEO-информация заголовка заголовка была отображена. Если вам нужно динамически отображать данные на сервере, вы можете запросить фоновые данные из файлов в каталоге pages и отобразить их в файл HeadSeo, передав значение через реквизиты.

Требование 2. Благоустройство маршрута

Функция пользовательского улучшения маршрутизации реализована с помощью пользовательской маршрутизации на стороне сервера. Например, на сайте Ухань (Ухань) маршрут, необходимый для доступа к домашней странице, выглядит следующим образом.

Город титульная страница насчет нас
Ухань /wuhan/index /wuhan/about
Шанхай /shanghai/index /shanghai/about
Нанкин /nanjing/index /nanjing/about

Создайте серверный файл сценария server.js, сервер использует Express в качестве сервера.

// 安装 express 服务端代理工具也一起安装了 http-proxy-middleware
cnpm i express http-proxy-middleware --save
const express = require('express')
const next = require('next')
const server = express()

const port = parseInt(process.env.PORT, 10) || 3000 // 设置监听端口
const dev = process.env.NODE_ENV !== 'production' // 判断当前开发环境
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {

    server.get('/:city', (req, res) => {
        const actualPage = '/index';
        const queryParams = { city: req.params.city}; // 通过 req 请求对象访问到路径上传过来的参数
        console.log(req.params)
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/index', (req, res) => {
        const actualPage = '/index';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/about', (req, res) => {
        const actualPage = '/about';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/posts/:id', (req, res) => {
      return app.render(req, res, '/posts', { id: req.params.id })
    })

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen(port, (err) => {
      if (err) throw err
      console.log(`> Ready on http://localhost:${port}`)
    })
})

Сценарий для изменения файла package.json выглядит следующим образом: затем запустите команду npm run ssrdev, чтобы открыть порт 3000, и теперь вы можете получить доступ к странице через улучшенный маршрут localhost:3000/wuhan/index.
localhost:3000/wuhan/about

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "ssrdev": "node server.js", // 可以通过nodemon 来代替node,这样server.js 文件修改后不需要重新运行脚本
    "ssrstart": "npm run build && NODE_ENV=production node server.js", // 需要先执行 npm run build
    "export": "npm run build && next export"
  },
  "dependencies": {
    "express": "^4.17.0",
    "http-proxy-middleware": "^0.19.1",
    "next": "^8.1.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  }
}

Требование 3: отображать разные данные в зависимости от разных городов

Отобразите домашнюю страницу соответствующего городского сайта в соответствии с географическим положением пользователя и получите данные о разных городах. Здесь начинается моделирование данных и сбор данных на стороне сервера. В этой проектной практике будут опробованы два метода моделирования данных.

  • json-server

  • mock.js (этот метод проще, будет добавлен позже)

Сначала установите json-сервер с открытым исходным кодом.

cnpm install -g json-server

Создайте новый файл макета в каталоге ssr, а затем создайте новый файл data.json под макетом.Данные файла выглядят следующим образом.

{
    "index":{
        "city":"wuhan",
        "id":1,
        "theme":"默认站点"
    },
    "posts": [
      { "id": 1, "title": "json-server", "author": "typicode" }
    ],
    "comments": [
      { "id": 1, "body": "some comment", "postId": 1 }
    ],
    "profile": { "name": "typicode" },
    "seo":{
        "title":"基于React.js 技术栈的服务端渲染框架Next.js 实战记录",
        "keywords":"Winyh, Next.js, React.js, Node.js",
        "description":"Next.js服务端渲染数据请求模拟页面测试"
    }
}

Создайте новый файл правил маршрутизации route.json в текущем каталоге и добавьте префикс /api/ к макету API. Типы файлов следующие

{
    "/api/*": "/$1"
}

Измените файл package.json и добавьте данные для имитации сценария командной строки.

{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "ssrdev": "nodemon server.js",
    "ssrstart": "npm run build && NODE_ENV=production nodemon server.js",
    "export": "npm run build && next export",
  + "mock": "cd ./mock && json-server --watch data.json --routes routes.json --port 4000"
  },
  "dependencies": {
    "express": "^4.17.0",
    "http-proxy-middleware": "^0.19.1",
    "next": "^8.1.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6"
  }
}

Запустите команду npm run mock, чтобы запустить фиктивный сервер данных для доступа к данным.

localhost:4000/api/seo

Сначала установите инструмент запроса ajax

cnpm install isomorphic-unfetch --save

Обновите содержимое файла pages/index.js до

import React, { Component } from 'react';
import Layout from "../components/Layouts/PcLayout"
import 'isomorphic-unfetch'

class index extends Component {
    constructor(props) {
		super(props);
		this.state = {
			city:"武汉"
		};
    }

    static async getInitialProps({ req }) {
        const res = await fetch('http://localhost:4000/api/seo')
        const seo = await res.json()
        return { seo }
    }

    componentDidMount(){
        console.log(this.props)
    }
    
    render(){
        const { seo } = this.props;
        return (
            <Layout seo={seo}>
                <div>Welcome to next.js!</div>
                <div>{seo.title}</div>
            </Layout>
        )
    }
}
export default index

Содержимое файла /Layouts/Pclayout.js изменено на

import HeadSeo from '../Common/HeadSeo'

export default ({ children, seo }) => (
  <div id="pc-container">
    <HeadSeo seo={ seo }></HeadSeo>
    { children }
  </div>
)

Содержимое файла /components/Common/HeadSeo.js изменено на

import Head from 'next/head'

export default ({seo}) =>
    <Head>
        <meta charSet="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="keywords" content={seo.keywords} />
        <meta name="description" content={seo.description} />
        <title>{seo.title}</title>
    </Head>

На этом этапе вы можете видеть напечатанные данные и отображаемые данные на этой странице.

Следующим шагом является определение отображаемого города страницы в соответствии с географическим положением пользователя.Этапы решения следующие [пока только метод, а код будет улучшен позже]

  • Сначала запросите Baidu open api, чтобы получить название города и уникальный код в соответствии с IP-адресом.
  • Запросите данные города, соответствующие уникальному коду, используя уникальный код в качестве параметра.
  • После того, как маршрут будет благоустроен, верните соответствующие данные страницы города на стойку регистрации для отображения.

Требование 4: Рендеринг разных страниц на стороне ПК/М

Основной принцип: судить о терминале по заголовку запроса user-agnet, а затем рендерить разные компоненты Создайте новую папку js в статической папке и создайте новый модуль класса инструмента util.js в папке js.Код выглядит следующим образом

// 根据 user-agent 请求头判断是否移动端
const util = {

    isMobile: (req) => {
        const deviceAgent = req.headers["user-agent"];
        return /Android|webOS|iPhone|iPod|BlackBerry/i.test(deviceAgent)
    },

};

module.exports  = util

Создайте новый файл mindex.js в папке pages в качестве домашней страницы для мобильного рендеринга.

import React, { Component } from 'react';
import Layout from "../components/Layouts/MLayout"
import 'isomorphic-unfetch'

class index extends Component {
    constructor(props) {
		super(props);
		this.state = {
			city:"武汉"
		};
    }

    static async getInitialProps({ req }) {
        const res = await fetch('http://localhost:4000/api/seo')
        const seo = await res.json()
        return { seo }
    }

    componentDidMount(){
        console.log(this.props)
    }
    
    render(){
        const { seo } = this.props;
        return (
            <Layout seo={seo}>
                <div>Welcome to next.js!</div>
                <div>移动端页面</div>
            </Layout>
        )
    }
}
export default index
    

Измените содержимое файла server.js следующим образом.

const express = require('express')
const next = require('next')
const server = express()

const util = require("./static/js/util");

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {

    server.get('/:city', (req, res) => {
        const actualPage = util.isMobile(req) ? '/mindex' : '/index'; // 这里是关键
        const queryParams = { city: req.params.city};
        console.log(req.params.city, actualPage)
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/index', (req, res) => {
        const actualPage = '/index';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/about', (req, res) => {
        const actualPage = '/about';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/posts/:id', (req, res) => {
      return app.render(req, res, '/posts', { id: req.params.id })
    })

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen(port, (err) => {
      if (err) throw err
      console.log(`> Ready on http://localhost:${port}`)
    })
})

Используйте браузер, чтобы открыть мобильный режим панели отладки, чтобы автоматически рендер мобильную страницу

Требование пятое: информация о конфигурации SEO

На самом деле, это в основном реализовано.Фронтдеск маршрутизирует параметры страницы через разные страницы, чтобы запросить начальный интерфейс данных первого экрана подстраницы, и запрос завершается в методе getInitialProps при рендеринге сервера. Например: /wuhan/index может получить SEO-информацию, настроенную для индексной страницы в фоновом режиме, в соответствии с индексом в качестве параметра. /wuhan/posts может использовать сообщения в качестве параметра для получения SEO-информации, настроенной в фоновом режиме для страницы сообщений.

Требование 6. Поддержка переключения среды разработки/формальной среды

Сервер server.js можно реализовать следующими способами

const dev = process.env.NODE_ENV !== 'production';

Клиент может быть реализован через конфигурационный файл next.config.js

/*
* @Author: winyh
* @Date:   2018-11-01 17:17:10
 * @Last Modified by: winyh
 * @Last Modified time: 2018-12-14 11:01:35
*/
const withPlugins = require('next-compose-plugins')
const path = require("path");
const sass = require('@zeit/next-sass')

const isDev = process.env.NODE_ENV  !== 'production'

console.log({
    isDev
})

// api主机 
const host = isDev ? 'http://localhost:4000':'http://localhost:4001'

const {
    PHASE_PRODUCTION_BUILD,
    PHASE_PRODUCTION_SERVER,
    PHASE_DEVELOPMENT_SERVER,
    PHASE_EXPORT,
} = require('next/constants');

const nextConfiguration = {
    //useFileSystemPublicRoutes: false, 
    //distDir: 'build',
    testConfig:"www",
    webpack: (config, options) => {

        config.module.rules.push({
            test: /\.(jpe?g|png|svg|gif|ico|webp)$/,
            use: [
              {
                loader: "url-loader",
                options: {
                  limit: 20000,
                  publicPath: `https://www.winyh.com/`,
                  outputPath: `/winyh/static/images/`,
                  name: "[name].[ext]"
                }
              }
            ]
        })
    
        return config;
    },

    serverRuntimeConfig: { // Will only be available on the server side
        mySecret: 'secret'
    },
    publicRuntimeConfig: { // Will be available on both server and client
        mySecret: 'client',
        host: host,
        akSecert:'GYxVZ027Mo0yFUahvF3XvZHZzAYog9Zo' // 百度地图ak 密钥
    }
}

module.exports = withPlugins([
    
    [sass, {
        cssModules: false,
        cssLoaderOptions: {
          localIdentName: '[path]___[local]___[hash:base64:5]',
        },
        [PHASE_PRODUCTION_BUILD]: {
          cssLoaderOptions: {
            localIdentName: '[hash:base64:8]',
          },
        },
    }]

], nextConfiguration)

pages/index.js изменяет код адреса хоста API через файл конфигурации, код выглядит следующим образом (позже запрос на выборку будет инкапсулирован в общедоступный метод)

import React, { Component } from 'react';
import Layout from "../components/Layouts/PcLayout"
import 'isomorphic-unfetch'
import getConfig from 'next/config' // next自带的配置方法
const { publicRuntimeConfig } = getConfig() // 取到配置参数

class index extends Component {
    constructor(props) {
		super(props);
		this.state = {
			city:"武汉"
		};
    }

    static async getInitialProps({ req }) {
        const res = await fetch(publicRuntimeConfig.host + '/api/seo') // 从配置文件里获取
        const seo = await res.json()
        return { seo }
    }

    componentDidMount(){
        console.log(this.props)
    }
    
    render(){
        const { seo } = this.props;
        return (
            <Layout seo={seo}>
                <div>Welcome to next.js!</div>
                <div>{seo.title}</div>
            </Layout>
        )
    }
}
export default index

Требование 7. Развертывание файла авторизации WeChat

При оплате или авторизации WeChat на веб-странице необходимо пройти проверку безопасности сервера WeChat.Сервер WeChat отправляет ключевой файл *.txt, который обычно находится в корневом каталоге проекта и должен поддерживать доступ, например : локальный: 3000/MP_verify_HjspU6daVebgWsvauH.txt

  • Установите доступ к корневому каталогу server.use(express.static(__dirname)), это слишком небезопасно, все файлы в корневом каталоге открыты

  • Добавьте метод для обработки файлов .txt в файле server.js.

server.get('*', (req, res) => {
const express = require('express')
const next = require('next')
const server = express()

const util = require("./static/js/util");

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {

    server.get('/:city', (req, res) => {
        const txt = req.url; // 获取请求路径
        // 这里需要做一个请求拦截判断
        if(txt.indexOf(".txt") > 0){
          res.sendFile(__dirname + `/${txt}`);
        }
        const actualPage = util.isMobile(req) ? '/mindex' : '/index';
        const queryParams = { city: req.params.city};
        console.log(req.params.city, actualPage)
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/index', (req, res) => {
        const actualPage = '/index';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/about', (req, res) => {
        const actualPage = '/about';
        const queryParams = { city: req.params.city};
        app.render(req, res, actualPage, queryParams);
    });

    server.get('/:city/posts/:id', (req, res) => {
      return app.render(req, res, '/posts', { id: req.params.id })
    })

    // server.get('*', (req, res) => {
    //   return handle(req, res)
    // })

    server.get('*', (req, res) => {
      const txt = req.url; // 获取请求路径
      if(txt.indexOf(".txt") > 0){
        res.sendFile(__dirname + `/${txt}`);
      } else {
        return handle(req, res)
      }
    })

    server.listen(port, (err) => {
      if (err) throw err
      console.log(`> Ready on http://localhost:${port}`)
    })
})

Создайте файл MP_verify_HjspU6daVebgWsvauH.txt в корневом каталоге для проверки результатов доступа браузера

Требование 8: Частичная обработка прокси-запроса Http

Добавьте следующий код в файл server.js для автоматического сопоставления прокси-сервера с http://api.test-proxy.com при доступе к маршруту /proxy/*.

const proxyApi = "http://api.test-proxy.com"
server.use('/proxy/*', proxy({ 
  target: proxyApi, 
  changeOrigin: true 
}));

Требование 9. Обработка перенаправления класса

Его нужно отображать при доступе к маршруту localhost:3000/winyhask.redirect.com/about?type_…контент на странице. Сначала установите инструмент cnpm и urllib --save

// 修改server.js 文件代码

server.get('/winyh', async (req, res) => {
  const agent  = req.header("User-Agent");
  const result = await urllib.request(
    'http://ww.redirect.com/about?type_id=3', 
    {   
      method: 'GET',
      headers: {
        'User-Agent': agent
      },
    })
    res.header("Content-Type", "text/html;charset=utf-8");
    
    res.send(result.data);// 需要获取result.data 不然显示到前台的数据时二进制 45 59 55 
})

Требование 10. Моделирование локальных данных

Как упоминалось в предыдущей статье, он был реализован

Требование одиннадцатое: метод развертывания проекта

В основном для записи файла Dockerfile локальный VsCode может начать отладку контейнера, последующую демонстрацию

FROM mhart/alpine-node

WORKDIR /app
COPY . .

RUN yarn install
RUN yarn build

EXPOSE 80

CMD ["node", "server.js"]

Окончательное резюме:

  • Есть еще много деталей, которые можно улучшить, я надеюсь, что это может помочь всем, и я также надеюсь комментировать, обмениваться информацией и учиться друг у друга.
  • Позже запрос данных будет изменен на Graphql.js. в моей статьеНовый способ взаимодействия GraphQL.js с серверомНаписал демонстрацию для начала работы с GraphQL.
Категории