用koa寫項目後臺遇到的bug及解決

用koa寫項目後臺遇到的bug及解決

  • import,exports使用ES6規範時,項目運行會報錯:

    原因:是因爲目前 NodeJs 只支持部分 ES6 的語法,有些 ES6 的語法還不支持,而 import 語法就是其中之一

    解決: 改爲CommonJs 的語法格式,諸如:const Koa = require('koa') module.exports = app

  • Error: get /login: middleware must be a function, not undefined

    分析:我的邏輯是將路由記錄寫在router裏,然後按API分成若干js文件,真正完成業務邏輯的部分放在了controllers層,對應某api_controller,bug中的/login是我的一個處理登錄邏輯的中間件

    在app.js中 :我將路由註冊:

    // routes 註冊路由
    app.use(user.routes(), user.allowedMethods())
    

    routes–>user.js中:

    const router = require('koa-router')()
    const user_controller = require('../controllers/user_controller')
    // koa-router提供一種router.prefix方法,此方法對於某一個router來說,是一個全局配置,此router的所有路徑都會自動被添加該前綴。
    router.prefix('/user')
    router.get('/login', user_controller.login)
    module.exports = router
    

    controllers–>user_controller中:

    const login = async(ctx,next) => {
        const req = ctx.request.body
        ctx.body = 'this is a users/login response'
    }
    module.exports = {
        login
    }
    

    最初沒有寫module.exports = {
    login
    }
    時就報了這個error!!!

    原因及解決:的原因是routes裏定義的APIrouter.get('/login', user_controller.login)和controllers裏的exports沒有對應上 !!!

  • port 3000 is already in use的一種可能原因:

    問題在於重複起調同一個端口,有的人的寫法是在app.js中寫app.listen(...),有的人會獨立建立一個js來描述端口的事宜,如:

    www.js:

    #!/usr/bin/env node
    
    /**
     * Module dependencies.
     */
    
    var app = require('../app')
    var debug = require('debug')('demo:server')
    var http = require('http')
    // var coinfig = require('../config')
    
    /**
     * Get port from environment and store in Express.
     */
    // 在端口3000監聽:
    var port = normalizePort(process.env.PORT || '3000')
    // app.set('port', port);
    
    /**
     * Create HTTP server.
     */
    
    var server = http.createServer(app.callback())
    
    /**
     * Listen on provided port, on all network interfaces.
     */
    
    server.listen(port)
    server.on('error', onError)
    server.on('listening', onListening)
    
    /**
     * Normalize a port into a number, string, or false.
     */
    
    function normalizePort (val) {
      var port = parseInt(val, 10)
    
      if (isNaN(port)) {
        // named pipe
        return val
      }
    
      if (port >= 0) {
        // port number
        return port
      }
    
      return false
    }
    
    /**
     * Event listener for HTTP server "error" event.
     */
    
    function onError (error) {
      if (error.syscall !== 'listen') {
        throw error
      }
    
      var bind = typeof port === 'string'
        ? 'Pipe ' + port
        : 'Port ' + port
    
      // handle specific listen errors with friendly messages
      switch (error.code) {
        case 'EACCES':
          console.error(bind + ' requires elevated privileges')
          process.exit(1)
          // eslint-disable-next-line no-unreachable
          break
        case 'EADDRINUSE':
          console.error(bind + ' is already in use')
          process.exit(1)
          // eslint-disable-next-line no-unreachable
          break
        default:
          throw error
      }
    }
    
    /**
     * Event listener for HTTP server "listening" event.
     */
    
    function onListening () {
      var addr = server.address()
      var bind = typeof addr === 'string'
        ? 'pipe ' + addr
        : 'port ' + addr.port
      debug('Listening on ' + bind)
    }
    
    

    以上兩種任寫一種即可,多些即會報這個錯,表示端口已經被佔用

  • 連接數據庫時,報了這個錯erroe no.2003 cant connect to mysql server on localhost

    原因是MySQL服務已經關閉

在這裏插入圖片描述

解決:右鍵啓動服務即可

  • 嘗試與vuecli2寫的前臺交互時出來一個錯誤:

    vuecli服務器正常顯示 DONE Compiled successfully in 224628ms,

    但是網頁控制檯顯示錯誤:Refused to load the image ‘http://localhost:8080/favicon.ico

    ’ because it violates the following Content Security Policy directive: “default-src ‘none’”. Note that ‘img-src’ was not explicitly set, so ‘default-src’ is used as a fallback.頁面只有Cannot GET /

    最後發現是曾經把vuecli2項目打包過,打包時時要把config–>index.js中的 assetsPublicPath: '/'改成`assetsPublicPath: ‘./’,因此現在解決這個問題就要把它統統改回來就沒有問題了

在這裏插入圖片描述

  • 重啓服務器時,koa這邊的項目突然變的奇慢無比,而且訪問API時會報404:

    發現是啓動時路徑寫錯了,出了點小問題,因爲要的路徑是當前路徑的父目錄的兄弟,所以它會繞彎子訪問,所以一開始訪問3000時沒有報錯只是很慢,到API就會404的原因

  • Access to XMLHttpRequest at ‘http://localhost:3000/user/login?user_name=1326&user_password=789456’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

    典型跨域報的錯誤,就算在本機上,端口不同也是需要跨域的(改成統一端口就佔用端口了)

    當域名、端口、協議有任意一個不一樣的時候就會存在跨域

    解決如下:

    npm install --save koa2-cors

    var Koa = require('koa');
    var cors = require('koa2-cors');
     
    var app = new Koa();
    app.use(cors({
      origin: function (ctx) {
        if (ctx.url === '/test') {
            return "*"; // 允許來自所有域名請求
        }
        return 'http://localhost:8080'; // 這樣就能只允許 http://localhost:8080 這個域名的請求了
      },
      exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
      maxAge: 5,
      credentials: true,
      allowMethods: ['GET', 'POST', 'DELETE'],
      allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
    }))
    
  • 曾經安裝了MySQL,那我還需要使用npm install -g mysql嗎?

    答案是需要的,mysql數據庫是存放數據的,裏面有庫和表;而npm安裝的是MySQL的驅動程序,你的應用通過這個驅動程序連接並操作mysql中的庫和表。

  • 連接好表後,需要使用Sequelize進行對數據庫表的映射,很多博客會教你如何寫,其實它是可以自動生成的:下圖是數據庫的表,我們需要給他們建立映射。

在這裏插入圖片描述

​ 需要全局安裝sequelize-auto:sequelize-auto

使sequelize-auto命令操作數據庫(MySQL):npm install -g tedious

根據sequelize-auto自動生成model且生成指定的表對應的js:(以studio表爲例)

sequelize-auto -h localhost -d ttms -u root -x 123456 -p 3306 -t studio

其中,

-h是你的數據庫IP地址

-d是數據庫庫名

-x是數據庫密碼

-p 是數據庫端口號

-t是需要映射的表名

但是,需要注意的是由於是自動生成的,有的地方還有問題,(例如自增長在映射里老是不會自動生成)使用時需要敏感一些,如有問題就手動寫一些語句輔助
在這裏插入圖片描述

  • xxx POST /user/register 500 368ms - ....cannot be an array or an object

這個錯基本都是少些了異步操作,需要補上一些await才行

給幾個例子:

在controllers–>user_controller.js裏使用:

// 註冊新用戶
const register = async(ctx,next) => {
    ctx.status = 200 // post 默認是404
    const req = ctx.request.body
    const user_name = req.user_name
    const phonenumber = req.phonenumber
    var password =await encrypt(req.user_password) // 此處若不寫await得到的將是一個promise對象
    console.log(password)
    // ctx.body = data
    let user = userModel.build({
        user_name,
        phonenumber,
        user_password: password
     });
     user = await user.save();     
     
} 

一開始沒寫var password =await encrypt(req.user_password)裏的await於是報了這個錯,我當時硬把結果String保存說可以的,但是打印出來是 promise:{…}然後就意識到應該這樣操作。

// 獲取打印票面信息
const getTicketByUserAndPlan = async(ctx,next) => {  
    const user_name = ctx.query.user_name    
    const plan_id = ctx.query.plan_id
    const userInfo = await getbUserId(userModel,user_name) // 注意await
    const user_id = userInfo[0].dataValues.user_id
    ctx.body = await ticketModel.findAll({  // 注意await
        where:{ user_id, plan_id},
        attributes: [ 'user_id', 'studio_name', 'startTime', 'endTime', 'seat_row', 'seat_col' ]
    })
}

上面代碼兩處不寫await也會報一樣的500的信息

  • POST時出現404的可能性:
    1. 路徑寫錯了
    2. ctx.status有問題
    3. 去看看路由那裏是不是寫成了GET
  • 當npm了很多次還是報錯Cannot find module …時,看看你npm的路徑,可能路徑就有問題

我之後會把這篇博客拆開,便於尋找對應的錯誤,這個就是做個總結了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章