Small program to quickly configure https service interface - the project is nodeJS to configure local https service, no need to download source code and no payment, directly use the openssh function of Git (pro-test effective)

background

Learning the development of Netease cloud music applets, using the teacher's node JS as the back-end server, the trial version of the online applet must have an https interface.

The next step is to configure the pitfalls and surprises discovered by configuring the NodeJs service https.

===== Follow up:

The https service of the applet cannot start with an ip address. The following process configuration is useless. If you still need to configure the https server, you can continue to read. If you don’t need it, please turn around here.

Configure https

Download and configure

key generation

1 Run the command: openssl genrsa -out privatekey.pem 1024

2 Run the command: openssl req -new -key privatekey.pem -out certrequest.csr

3 Run the command: openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem

At this point, three key files are generated in the project folder

Copy the three key files generated above to the node project and create a startup script

 Start the nodeJS backend service:

Encountered a problem Openss does not know

1. 'Openssl' is not recognized as an internal or external command

The reason is that Openssl is not installed in the windows system. This is not built-in with the system. You need to download and install it yourself.

Source URL  /source/index.html

Download: This download compares, wait slowly

       1) Website: Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions , click the picture to select the full version;

 Or use Baidu Netdisk to download:

Link: https://pan.baidu.com/s/1PRw1rEDP853KkujUJdaAKA?pwd=8qz0 
Extraction code: 8qz0

After the download is complete install: ;

 After the installation is complete, a reward of 10 yuan is required, and the one-time configuration is completed. in spite of.

The administrator first checks the installation status: the display is still unknown

Want to collect money, give up~~~

Quickly realize the configuration key (when git is already installed) Surprise! ! ! ! !

There is no solution, and then I searched the computer and found that there are openSSh in many places,

I used git to configure the ssh key before, thinking about whether I can use this git software to realize it now, then I found a directory at random, right-clicked to open the git control window

Then in the git bath batch window, execute 3 key file generation commands:

1 Run the command: openssl genrsa -out privatekey.pem 1024

2 Run the command: openssl req -new -key privatekey.pem -out certrequest.csr

3 Run the command: openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem

Finally execute:

openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem 

Generate 3 files and copy them to a new key directory under the project root directory

 certrequest.csr

privatekey.pem

certificate.pem

 Then create a service startup script:

http and https serve source code at the same time: Create httpsAndHttp.js in the root directory of the project, and then copy the following code into it,

var SSLPORT = 499; //https port When https uses the default port, the following error may appear. Change the default 443 to other unoccupied ports to access normally.
var app = require('express')();
var fs = require('fs');
var http = require('http');
var https = require('https');

var privateKey  = fs.readFileSync('./key/privatekey.pem', 'utf8'); //密钥路径,编码
var certificate = fs.readFileSync('./key/certificate.pem', 'utf8');
var credentials = {key: privateKey, cert: certificate};

var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
var PORT = 3030; //http 端口
// var SSLPORT = 443; //https 端口
var SSLPORT = 499; //https 端口

httpServer.listen(PORT, function() {
  console.log('HTTP Server is running on: http://localhost:%s', PORT);
});

httpsServer.listen(SSLPORT, function() {
  console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});

// Welcome
app.get('/', function(req, res) {
  if(req.protocol === 'https') {
    res.status(200).send('Welcome https!');
  }
  else {
    res.status(200).send('Welcome http!');
  }
});

 Encryption does not use 443, but changes to port 499 to prevent conflicts. Then, in the terminal command window in webstorm, execute

node httpsAndHttp.js

 The startup is successful, open the verification: OK--- happy

Open the webpage, enter 

https://localhost:499/

 The prompt is not safe, don't worry about it, click Advanced, there is a button to continue accessing.

Verify that this method is ok, and then configure the back-end server of NetEase Cloud Open Source

Configure Netease Cloud Music backend https

Now configure the back-end service of the applet that is being studied, the source code Github open source project: use: NetEase Cloud Music NodeJS version API

 Backend interface usage reference:

Shang Silicon Valley WeChat Mini Program Development Imitates NetEase Cloud Music App Mini Program Backend Interface Server Construction_Lan.W's Blog-CSDN Blog

Modify the server.js of the original project, mainly to add 3 key files to import, and change the monitoring to https monitoring

var privateKey = fs.readFileSync('./key/privatekey.pem', 'utf8') //key path, encoding
var certificate = fs.readFileSync('./key/certificate.pem', 'utf8')
var credentials = {key: privateKey, cert: certificate}
// var SSLPORT = 443; //https port
var SSLPORT = 488 //https port When https uses the default port, the following error may occur, change the default 443 to something else The occupied port can be accessed normally.

....//Listen to the address, configure https

const appExt = app
// httpServer.listen
console.log(">> Set client request monitoring", port, host)
appExt.server = app.listen(port, host, () => {
  console.log(`server running @ http://${host ? host : 'localhost'}:${port}`)
})
//add by lani
var https = require('https');
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(SSLPORT, host, () => {
  console.log(`server running @ https://${host ? host : 'localhost'}:${SSLPORT}`)
})

 The entire file code after server.js modification

const fs = require('fs')
const path = require('path')
const express = require('express')
const request = require('./util/request')
const packageJSON = require('./package.json')
const exec = require('child_process').exec
const cache = require('./util/apicache').middleware
const {cookieToJson} = require('./util/index')
const fileUpload = require('express-fileupload')
const decode = require('safe-decode-uri-component')
// add by lani 添加3个密钥文件
var privateKey = fs.readFileSync('./key/privatekey.pem', 'utf8') //密钥路径,编码
var certificate = fs.readFileSync('./key/certificate.pem', 'utf8')
var credentials = {key: privateKey, cert: certificate}
// var SSLPORT = 443; //https 端口
var SSLPORT = 488 //https 端口 当 https 使用默认端口的时候可能会出现如下报错,把默认443修改成其它不被占用的端口就可以正常访问。


/**
 * The version check result.
 * @readonly
 * @enum {number}
 */
const VERSION_CHECK_RESULT = {
  FAILED: -1,
  NOT_LATEST: 0,
  LATEST: 1,
}

/**
 * @typedef {
   
   {
 *   identifier?: string,
 *   route: string,
 *   module: any
 * }} ModuleDefinition
 */

/**
 * @typedef {
   
   {
 *   port?: number,
 *   host?: string,
 *   checkVersion?: boolean,
 *   moduleDefs?: ModuleDefinition[]
 * }} NcmApiOptions
 */

/**
 * @typedef {
   
   {
 *   status: VERSION_CHECK_RESULT,
 *   ourVersion?: string,
 *   npmVersion?: string,
 * }} VersionCheckResult
 */

/**
 * @typedef {
   
   {
 *  server?: import('http').Server,
 * }} ExpressExtension
 */

/**
 * Get the module definitions dynamically.
 *
 * @param {string} modulesPath The path to modules (JS).
 * @param {Record<string, string>} [specificRoute] The specific route of specific modules.
 * @param {boolean} [doRequire] If true, require() the module directly.
 * Otherwise, print out the module path. Default to true.
 * @returns {Promise<ModuleDefinition[]>} The module definitions.
 *
 * @example getModuleDefinitions("./module", {"album_new.js": "/album/create"})
 */
async function getModulesDefinitions(
  modulesPath,
  specificRoute,
  doRequire = true,
) {
  const files = await fs.promises.readdir(modulesPath)
  const parseRoute = (/** @type {string} */ fileName) =>
    specificRoute && fileName in specificRoute
      ? specificRoute[fileName]
      : `/${fileName.replace(/\.js$/i, '').replace(/_/g, '/')}`

  const modules = files
    .reverse()
    .filter((file) => file.endsWith('.js'))
    .map((file) => {
      const identifier = file.split('.').shift()
      const route = parseRoute(file)
      const modulePath = path.join(modulesPath, file)
      const module = doRequire ? require(modulePath) : modulePath

      return {identifier, route, module}
    })

  return modules
}

/**
 * Check if the version of this API is latest.
 *
 * @returns {Promise<VersionCheckResult>} If true, this API is up-to-date;
 * otherwise, this API should be upgraded and you would
 * need to notify users to upgrade it manually.
 */
async function checkVersion() {
  return new Promise((resolve) => {
    exec('npm info NeteaseCloudMusicApi version', (err, stdout) => {
      if (!err) {
        let version = stdout.trim()

        /**
         * @param {VERSION_CHECK_RESULT} status
         */
        const resolveStatus = (status) =>
          resolve({
            status,
            ourVersion: packageJSON.version,
            npmVersion: version,
          })

        resolveStatus(
          packageJSON.version < version
            ? VERSION_CHECK_RESULT.NOT_LATEST
            : VERSION_CHECK_RESULT.LATEST,
        )
      }
    })

    resolve({
      status: VERSION_CHECK_RESULT.FAILED,
    })
  })
}

/**
 * Construct the server of NCM API.
 *
 * @param {ModuleDefinition[]} [moduleDefs] Customized module definitions [advanced]
 * @returns {Promise<import("express").Express>} The server instance.
 */
async function consturctServer(moduleDefs) {
  console.log(">>>开始创建请求配置")
  const app = express()  // express, 同一个app
  const {CORS_ALLOW_ORIGIN} = process.env
  app.set('trust proxy', true)

  /**
   * CORS & Preflight request
   */
  app.use((req, res, next) => {
    if (req.path !== '/' && !req.path.includes('.')) {
      res.set({
        'Access-Control-Allow-Credentials': true,
        'Access-Control-Allow-Origin':
          CORS_ALLOW_ORIGIN || req.headers.origin || '*',
        'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
        'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
        'Content-Type': 'application/json; charset=utf-8',
      })
    }
    req.method === 'OPTIONS' ? res.status(204).end() : next()
  })

  /**
   * Cookie Parser
   */
  app.use((req, _, next) => {
    req.cookies = {}
    //;(req.headers.cookie || '').split(/\s*;\s*/).forEach((pair) => { //  Polynomial regular expression //
    ;(req.headers.cookie || '').split(/;\s+|(?<!\s)\s+$/g).forEach((pair) => {
      let crack = pair.indexOf('=')
      if (crack < 1 || crack == pair.length - 1) return
      req.cookies[decode(pair.slice(0, crack)).trim()] = decode(
        pair.slice(crack + 1),
      ).trim()
    })
    next()
  })

  /**
   * Body Parser and File Upload
   */
  app.use(express.json())
  app.use(express.urlencoded({extended: false}))

  app.use(fileUpload())

  /**
   * Serving static files
   */
  app.use(express.static(path.join(__dirname, 'public')))

  /**
   * Cache
   */
  app.use(cache('2 minutes', (_, res) => res.statusCode === 200))

  /**
   * Special Routers
   */
  const special = {
    'daily_signin.js': '/daily_signin',
    'fm_trash.js': '/fm_trash',
    'personal_fm.js': '/personal_fm',
  }

  /**
   * Load every modules in this directory
   */
  const moduleDefinitions =
    moduleDefs ||
    (await getModulesDefinitions(path.join(__dirname, 'module'), special))

  for (const moduleDef of moduleDefinitions) {
    // Register the route.
    app.use(moduleDef.route, async (req, res) => {
      ;[req.query, req.body].forEach((item) => {
        if (typeof item.cookie === 'string') {
          item.cookie = cookieToJson(decode(item.cookie))
        }
      })

      let query = Object.assign(
        {},
        {cookie: req.cookies},
        req.query,
        req.body,
        req.files,
      )

      try {
        const moduleResponse = await moduleDef.module(query, (...params) => {
          // 参数注入客户端IP
          const obj = [...params]
          let ip = req.ip

          if (ip.substr(0, 7) == '::ffff:') {
            ip = ip.substr(7)
          }
          // console.log(ip)
          obj[3] = {
            ...obj[3],
            ip,
          }
          return request(...obj)
        })
        console.log('>> 收到请求, [OK]', decode(req.originalUrl))

        const cookies = moduleResponse.cookie
        if (!query.noCookie){
          if (Array.isArray(cookies) && cookies.length > 0) {
            if (req.protocol === 'https') {
              // Try to fix CORS SameSite Problem
              console.log(">>> run https")
              res.append(
                'Set-Cookie',
                cookies.map((cookie) => {
                  return cookie + '; SameSite=None; Secure'
                }),
              )
            } else {
              console.log(">>> run http")
              res.append('Set-Cookie', cookies)
            }
          }
        }
        res.status(moduleResponse.status).send(moduleResponse.body)
      } catch (/** @type {*} */ moduleResponse) {
        console.log('[ERR]', decode(req.originalUrl), {
          status: moduleResponse.status,
          body: moduleResponse.body,
        })
        if (!moduleResponse.body) {
          res.status(404).send({
            code: 404,
            data: null,
            msg: 'Not Found',
          })
          return
        }
        if (moduleResponse.body.code == '301')
          moduleResponse.body.msg = '需要登录'
        if (!query.noCookie) {
          res.append('Set-Cookie', moduleResponse.cookie)
        }

        res.status(moduleResponse.status).send(moduleResponse.body)
      }
    })
  }
  console.log(">>请求服务 初始化完成 。")
  return app
}

/**
 * Serve the NCM API.
 * @param {NcmApiOptions} options
 * @returns {Promise<import('express').Express & ExpressExtension>}
 */
async function serveNcmApi(options) {
  const port = Number(options.port || process.env.PORT || '3000')
  const host = options.host || process.env.HOST || ''

  const checkVersionSubmission =
    options.checkVersion &&
    checkVersion().then(({npmVersion, ourVersion, status}) => {
      if (status == VERSION_CHECK_RESULT.NOT_LATEST) {
        console.log(
          `最新版本: ${npmVersion}, 当前版本: ${ourVersion}, 请及时更新`,
        )
      }
    })
  const constructServerSubmission = consturctServer(options.moduleDefs)

  const [_, app] = await Promise.all([
    checkVersionSubmission,
    constructServerSubmission,
  ])

  /** @type {import('express').Express & ExpressExtension} */
  const appExt = app
  // httpServer.listen
  console.log(">> 设置客户端请求监听",port,host)
  appExt.server = app.listen(port, host, () => {
    console.log(`server running @ http://${host ? host : 'localhost'}:${port}`)
  })
  //add by lani
  var https = require('https');
  var httpsServer = https.createServer(credentials, app);
  httpsServer.listen(SSLPORT, host, () => {
    console.log(`server running @ https://${host ? host : 'localhost'}:${SSLPORT}`)
  })

  return appExt
}

module.exports = {
  serveNcmApi,
  getModulesDefinitions,
}
After the configuration is complete, open cmd and enter the current project directory to execute the service startup command: node app.js

 Run the test:

 Then you can happily use the trial version of the applet to call the https interface.

 Open postman, and change the http to https protocol, which was used to test the recommended playlist last time. Execute again, and the data is perfect.

The applet sets the domain name:

ip no solution. 

 Reference: node configuration local https service_cainiaoyizhan 2020 blog-CSDN blog

Guess you like

Origin blog.csdn.net/LlanyW/article/details/131360006