@lzwme/captcha-cv-ocr
Version: 
Verification code identification based on OCR (Tesseract) and CV (OpenCV)
100 lines (82 loc) • 3.72 kB
JavaScript
/*
 * @Author: renxia
 * @Date: 2023-12-29 11:45:31
 * @LastEditors: renxia
 * @LastEditTime: 2024-01-06 12:58:01
 * @Description: 
 */
const http = require('node:http');
const url = require('node:url');
const path = require('node:path');
const fs = require('node:fs');
const { findFreePort, color } = require('@lzwme/fe-utils');
const Cvocr = require('./Cvocr');
const { logger, getCodesList } = require('./utils');
async function createServer({ port, baseDir = process.cwd() } = {}) {
  if (!port) port = process.env.PORT || await findFreePort();
  const clientServer = http.createServer(async (req, res) => {
    const corsHeaders = {
      'Access-Control-Allow-Origin': req.headers.origin || '*',
      'Content-Type': 'application/json',
      'Access-Control-Allow-Headers': 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With',
    };
    const data = [];
    if (req.method == 'OPTIONS') return res.writeHead(200, corsHeaders).end('');
    req.on('data', chunk => data.push(chunk));
    req.on('end', async () => {
      const reqUrl = url.parse(req.url);
      let body = data.join('');
      try {
        if (data.length > 0) body = JSON.parse(body);
      } catch {}
      if (body) logger.debug(body);
      if (reqUrl.pathname === '/ocr' && body) {
        const result = { errmsg: '', code: 0 };
        const codesList = getCodesList();
        if (!body.mode) body.mode = 'simplest';
        if (body.mode === 'slide_match') body.base64 = body.slideBase64 || body.base64;
        if (!body.base64) {
          result.errmsg = '未指定图片 base64 参数值';
        } else if (!body.mode || !codesList.includes(body.mode)) {
          result.errmsg = `请指定正确的 mode 模式`;
        }
        if (!result.errmsg) {
          ['base64', 'slideBase64', 'originalBase64'].forEach(key => {
            if (body[key] && !/data:image\/[a-zA-Z]*;base64,([^"]*)/.test(body[key])) body[key] = `data:image/jpg;base64,${body[key]}`;
          });
          try {
            result.data = await new Cvocr(body.mode).recognize(body.base64, body.originalBase64);
          } catch (error) {
            result.errmsg = typeof error === 'string' ? error : error.message || 'OCR识别处理异常';
          }
        }
        if (result.errmsg && !result.code) result.code = -1;
        res.writeHead(200, { ...corsHeaders });
        res.end(JSON.stringify(result));
        return;
      }
      let filePath = path.join(baseDir, reqUrl.pathname);
      if (!reqUrl.pathname.includes('.')) filePath = path.join(filePath, 'index.html');
      if (!fs.existsSync(filePath)) filePath = path.resolve(baseDir, 'index.html');
      if (fs.existsSync(filePath)) {
        if (reqUrl.pathname.endsWith('.js')) {
          res.writeHead(200, { 'Content-Type': 'application/x-javascript' });
        } else if (reqUrl.pathname.endsWith('.json')) {
          res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        } else if (/\.png|jpg|gif|webp$/.test(reqUrl.pathname)) {
          res.writeHead(200, { 'Content-Type': 'image/*' });
        } else if (reqUrl.pathname.endsWith('.css')) {
          res.writeHead(200, { 'Content-Type': 'text/css; charset=utf-8' });
        } else {
          res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        }
        res.end(fs.readFileSync(filePath));
      } else {
        res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end('请查阅使用文档:' + require('../package.json').homepage);
      }
    });
  });
  return clientServer.listen(port, () => logger.log('SERVER LISTEN ON PORT', color.greenBright(port)));
}
exports.createServer = createServer;