You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移Clarifai API密钥至后端后人脸检测失效,报TypeError错误

问题

为避免Clarifai API密钥在控制台暴露,将人脸检测的API密钥迁移至后端后,人脸检测功能完全失效,控制台报错:

TypeError: data.outputs is undefined
calculateFaceLocation App.js:49
onButtonSubmit App.js:95
promise callback*./src/App.js/</App/this.onButtonSubmit App.js:72
React 23
js index.js:8
js main.chunk.js:2298
Webpack 7

后端主文件代码

const express = require('express');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt-nodejs');
const cors = require('cors');
const knex = require('knex');

const register = require('./controllers/register');
const signin = require('./controllers/signin');
const profile = require('./controllers/profile');
const image = require('./controllers/image');

const db = knex({
    client: 'pg',
    connection: {
        host : '127.0.0.1',
        user : 'postgres',
        port: 5432,
        password : 'Moshe6700',
        database : 'smart-brain'
    }
});

const app = express();

app.use(bodyParser.json())
app.use(cors())

app.get('/', (req, res) => {res.send(database.users) })
app.post('/signin',  (req, res) => {signin.handleSignin(req, res, db, bcrypt)})
app.post('/register',  (req, res) => {register.handleRegister(req, res, db, bcrypt)})
app.get('/profile/:id', (req, res) => {profile.handleProfile(req, res, db)})
app.put('/image', (req, res) => {image.handleImage(req, res, db)})
app.post('/imageurl', (req, res) => {image.handleApiCall(req, res)})

app.listen(3001, () => {
    console.log('app is running on port 3001')
})

后端image.js代码

const Clarifai = require('clarifai');

const app = new Clarifai.App({
  apiKey: '489560069986431e89aa152fe709ba94'
});

const handleApiCall = (req, res) => {
    app.models
   .predict(Clarifai.FACE_DETECT_MODEL, req.body.input)
   .then(data => {
    res.json(data);
   })
   .catch(err => res.status(400).json('unable to work with API'))
}

const handleImage = (req, res, db) => {
    const { id } = req.body;
    db('users').where('id', '=', id)
    .increment('entries', 1)
    .returning('entries')
    .then(entries => {
        res.json(entries[0].entries)
    })
    .catch(err => res.status(400).json('unable to get entries'))
  }

  module.exports = {
    handleImage:handleImage,
    handleApiCall:handleApiCall
  }

前端App.js代码

import React, {Component} from 'react';
import Navigation from './components/Navigation/Navigation';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Rank from './components/Rank/Rank';
import Signin from './components/Signin/Signin';
import Register from './components/Register/Register';
import './App.css';

const intialState = {
      input: '',
      imageUrl: '',
      box: {},
      route: 'signin',
      isSignedIn: false,
      user: {
        id: '',
        name: '',
        email: '',
        entries: 0,
        joined: ''
      }
    }

class App extends Component {
  constructor() {
    super();
    this.state = intialState
  }

  loadUser = (data) => {
    this.setState({user: {
      id: data.id,
      name: data.name,
      email: data.email,
      entries: data.entries,
      joined: data.joined
    }})
  }

  calculateFaceLocation =(data) => {
    console.log(data)
   const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
   const image = document.getElementById('inputimage');
   const width = Number(image.width);
   const height = Number(image.height);
   return {
    leftCol: clarifaiFace.left_col * width,
    topRow: clarifaiFace.top_row * height,
    rightCol: width - clarifaiFace.right_col * width,
    bottomRow: height - clarifaiFace.bottom_row * height,
  }
}

displayFaceBox = (box) => {
  console.log(box)
  this.setState({box: box});
}

onInputChange = (event) => {
  this.setState({input: event.target.value})
}

onButtonSubmit = () => {
  this.setState({imageUrl: this.state.input})
   fetch('http://localhost:3001/imageurl', {
        method: 'post',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          input: this.state.input
        })
      })
   .then(response => response.json())
  .then( response => {
    if (response) {
      fetch('http://localhost:3001/image', {
        method: 'put',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          id: this.state.user.id
        })
      })
      .then(response => response.json())
      .then(count => {
        this.setState(Object.assign(this.state.user, { entries: count}))
      })
      .catch(console.log)
    }
    this.displayFaceBox(this.calculateFaceLocation(response))
  })
  .catch(err => console.log(err));

}

onRouteChange = (route) => {
  if (route === 'signout') {
    this.setState(intialState)
  } else if (route === 'home') {
    this.setState({isSignedIn: true})
  }
  this.setState({route:route});
}

render() {
  return (
    <div className="App">
    <Navigation isSignedIn={this.state.isSignedIn} onRouteChange={this.onRouteChange} />
    { this.state.route === 'home' 
    ? <div>
    <Logo />
    <Rank 
    name={this.state.user.name} 
    entries={this.state.user.entries}/>
    <ImageLinkForm  
    onInputChange={this.onInputChange}
    onButtonSubmit={this.onButtonSubmit} />
    <FaceRecognition box={this.state.box} imageUrl={this.state.imageUrl}/>
    </div>
    :(
      this.state.route === 'signin'
      ?<Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange} />
      :<Register loadUser={this.loadUser} onRouteChange={this.onRouteChange} />
      )
  }
  </div>
  );
}
}

export default App;
问题原因分析
  • 后端调用Clarifai API失败时,返回的是字符串'unable to work with API',前端会将这个字符串传入calculateFaceLocation函数,但字符串没有outputs属性,直接触发报错。
  • 前端的条件判断if (response)逻辑失效:即使后端返回错误字符串,response依然为真,会继续执行人脸位置计算逻辑,而非进入错误处理分支。
  • 前端更新用户entries的方式不符合React规范:直接通过Object.assign(this.state.user, ...)修改state对象,但这不是当前报错的直接原因。
修复方案

1. 后端返回格式统一修改

将错误返回改为对象格式,方便前端识别区分成功/失败状态:

// image.js中handleApiCall的catch部分修改为
.catch(err => res.status(400).json({ success: false, error: 'unable to work with API' }))

// 成功返回也统一格式
.then(data => {
  res.json({ success: true, data: data });
})

2. 前端逻辑调整

在处理/imageurl响应时,先判断请求是否成功,再执行后续逻辑:

// onButtonSubmit中的then回调修改为
.then(response => {
  if (response.success) {
    fetch('http://localhost:3001/image', {
      method: 'put',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        id: this.state.user.id
      })
    })
    .then(response => response.json())
    .then(count => {
      // 正确更新state的方式
      this.setState(prevState => ({
        user: {
          ...prevState.user,
          entries: count
        }
      }))
    })
    .catch(console.log)
    // 传入正确的data字段
    this.displayFaceBox(this.calculateFaceLocation(response.data))
  } else {
    console.log(response.error);
    // 可在此添加用户可见的错误提示
  }
})

内容的提问来源于stack exchange,提问作者Morris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:27:39