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

react-qr-reader无法识别部分自制二维码的问题排查求助

二维码扫描与生成问题排查及解答

问题描述

我在实现二维码验证功能时遇到以下问题:

  • 为40名用户生成的二维码中,有2个无法被react-qr-reader扫描识别,但其他扫码APP可以正常读取这些二维码的数据
  • 尝试将二维码分辨率调整至2000px后问题仍未解决
  • 在线工具QR-monkey生成的二维码可被我的扫描器正常识别

需要协助定位问题,同时想了解:

  1. 能识别这些二维码的APP使用的是什么类型的扫描器?
  2. 为何在线生成的二维码可被我的扫描器识别,而自制的不行?

相关代码

Scanner组件

const Scanner = (props) => {
  const [startScan, setStartScan] = useState(false);
  const [loadingScan, setLoadingScan] = useState(false);
  const [data, setData] = useState("");

  const handleScan = async(scanData) => {
    console.log(`loaded data data`, scanData);
    if (scanData && scanData !== "") {
      setLoadingScan(true);
      console.log(`loaded >>>`, scanData);
      const resData= JSON.parse(scanData)
      console.log(resData);
      setStartScan(false);
      setData(resData);
      setLoadingScan(false);
    }
  };

  const View = (e) => {
    navigate('/View')
  }

  const handleError = (err) => {
    console.error(err);
    navigate('/Scan')
  };
  
  const handleVerify = async(e) =>{
    setisverifying(true)

    const response = await axios({
      method:'post',
      url: 'verifyurl',
      data: data
    }).then(res => {
      console.log(res);
      if (res.status == 201) {
        navigate('/Success', {
          state:{
            name:res.data.resName,
            taken:res.data.resTaken,
            preference:res.data.resPreference,
            team:res.data.resTeam,
          }
        })
      }
    }).catch(err => {
      console.log(err);
    })
    setisverifying(false)
  }
  
  return (
    <div className="login-box">
      <h2>Scanner</h2>
      <button className='scanButton'
        onClick={() => {
          setStartScan(!startScan);
          setData('')
        }}
      >
        {startScan? "Stop Scan": "Start Scan"}
      </button>
      {startScan && (
        <>
          <QrReader
            delay={100}
            onError={handleError}
            onScan={handleScan}
            style={{ width: "100%", height: "100%" }}
          />
        </>
      )}
      {loadingScan && <CircularProgress />}

      {data !== "" && (
        <table className='tTable'>
          <tbody className='Ttbody' >
            <tr className='Ttr'>
              <p>Name</p>
              <td className='Ttd' >{data.state.name}</td>
            </tr>
            <tr className='Ttr'>
              <p>Team</p>
              <td className='Ttd'>{data.team}</td>
            </tr>
          </tbody>
        </table>
      )}
      {isverifying && <CircularProgress />}
      {data !=="" && <button className='scanButton' type="" onClick={handleVerify} >Verify</button>}
      
      <button className='scanButton' onClick={View}>View</button>
    </div>
  );
};

export default Scanner;

Generator.js

function QrCodeGenerator() {
  const [state, setState] = useState({
      name:'',
      phone:'',
      email:''
  });
  const [team, setTeam] = useState('');
  const [qr, setQr] = useState('');
  const [loading, setLoading] = useState(false);
  const [success, setSuccess] = useState(false);
  const [err, setErr] = useState(false);
  const [errMsg, seterrMsg] = useState('');
  
  const teams = [
    {value:'Greeters', label:'Greeters'},
    {value:'Cleaning', label:'Cleaning'},
  ]

  const GenerateQRCode = (e) => {
    e.preventDefault()
    const value = JSON.stringify({state, team})

    QRCode.toDataURL(value, {
            margin: 2,
            color: {
                dark: '#000000',
                light: '#ffffff'
            },
            width: 2000,
            height:2000
        }, (err, value) => {
            if (err) return console.error(err)    
            console.log(value)
            setQr(value)
        })
    }

  function handleChange(event) {
      const res = event.target.value;
      setState({
          ...state,
          [event.target.name]: res
      })
  }

  const handleSelect = (e) => {
    setTeam(e.value)
  }
  
  const handleSubmit = async(e) =>{
    e.preventDefault()
    if (team=='') {
      alert("Team is Required")
    }
    else{
      setLoading(true)
      const data = {state, team}
      const response = await axios({
        method:'post',
        url: "submitURL",
        data: data
      })
      .then(res => {
        console.log(res);
        if(res.status==201){
          setSuccess(true)
          setLoading(false)
        }
      })
      .catch(err => {
        console.log(err);
        if (err.response.status==406) {
          setErr(true)
          seterrMsg("The volunteer already exists!")
        }
        else{
          alert('There is an internal Server error. Kindly report to the IT team')
        }
      })
      setState({
        name:'',
        phone:'',
        email:''
      })
      setTeam('')
      setLoading(false)
    }
  }

  const handleSuccess = (e) =>{
    setSuccess(false)
  }

  return (
    <div className='login-box'>
        <form onSubmit={GenerateQRCode}>
          <input name='name' id='name' placeholder='Full Name' pattern="^(\w+)\s(\w+)$" value={state.name} onChange={handleChange} required />
          <input name='phone' id='phone' placeholder='Phone' type='tel' pattern="(6|7|8|9)\d{9}$" value={state.phone} onChange={handleChange} required='true'/>
          <input name='email' id='mail' placeholder='Email' type='email'  value={state.email} onChange={handleChange} required />
          <br/>
          <Select
            className='SelectTeam'
            closeMenuOnSelect={true}
            isMulti={false}
            options={teams}
            name='team'
            onChange={handleSelect}
          />
          <button type='submit' >Generate</button>
        </form>  
        {qr && (
          <>
            <img src={qr} alt='' className='qrimg' id='can'/>
            <a href={qr} download={`${state.name}.png`} ><button value="Download" >Download</button></a>
          </>
        )}
        {loading ?  <CircularProgress /> : <button onClick={handleSubmit}>Submit</button>}
        <br/>
    </div>
  )
}

export default QrCodeGenerator

问题定位与分析

1. 二维码生成参数差异

在线工具(如QR-monkey)默认采用高兼容参数,而你的自制生成器存在参数优化缺失:

  • 纠错级别:你当前生成代码未指定纠错级别(默认是低级别L,容错率7%),如果那2个二维码的数据复杂或生成时存在微小失真,低容错率会导致react-qr-reader识别失败;而专业APP的扫描引擎支持更高容错
  • 数据格式:JSON.stringify生成的字符串可能包含特殊字符(比如姓名中的非ASCII字符),未做转义处理可能导致react-qr-reader解析异常

2. react-qr-reader的局限性

react-qr-reader底层依赖jsQR这类Web端扫描库,和专业APP的原生引擎差距明显:

  • 专业APP使用iOS的AVFoundation或Android的ZXing/Mobile Vision原生API,具备更强的图像预处理、畸变校正能力
  • Web端扫描受限于浏览器摄像头性能、图像压缩率,容错率远低于原生引擎

3. 代码中的潜在问题

  • Generator.js:GenerateQRCode中value变量的定义位置错误,原代码中value在函数外定义,可能导致生成的二维码数据不是最新的用户输入
  • Scanner组件:handleScan中直接JSON.parse未做错误捕获,若扫描到的字符串格式异常,会直接抛出错误但无处理,表现为识别失败

针对疑问的解答

  1. 能识别的APP使用的扫描器类型:
    主流扫码APP(微信、支付宝等)使用原生平台内置扫描引擎:

    • iOS:基于Apple官方AVFoundation框架的二维码识别模块,经过大量优化,容错能力强
    • Android:大多集成Google开源的ZXing库或Mobile Vision API,部分厂商会做二次优化
      这些原生引擎在图像解析、容错处理上远优于Web端的jsQR库
  2. 在线生成二维码可识别的原因:
    在线工具默认采用高兼容配置:

    • 默认使用高纠错级别(Q或H级,容错率25%-30%),即使二维码有微小损坏也能识别
    • 严格遵循二维码国际标准,优化模块大小、边距比例,适配绝大多数扫描器
    • 对数据内容做兼容性处理,避免出现解析异常的特殊格式

修复建议

1. 优化二维码生成参数

在QRCode.toDataURL中添加高纠错级别参数:

QRCode.toDataURL(value, {
    margin: 2,
    color: {
        dark: '#000000',
        light: '#ffffff'
    },
    width: 2000,
    height: 2000,
    errorCorrectionLevel: 'H' // 设置最高容错级别
}, (err, value) => {
    // 现有逻辑
})

2. 修正Generator.js的变量定义问题

将value变量移至GenerateQRCode函数内部,确保生成最新的用户数据:

const GenerateQRCode = (e) => {
  e.preventDefault()
  // 移至函数内部,确保使用最新的state和team值
  const value = JSON.stringify({state, team})
  // 后续生成逻辑
}

3. 优化Scanner组件的错误处理

添加JSON.parse的错误捕获,避免解析失败导致流程中断:

const handleScan = async(scanData) => {
  console.log(`loaded data data`, scanData);
  if (scanData && scanData !== "") {
    setLoadingScan(true);
    console.log(`loaded >>>`, scanData);
    try {
      const resData= JSON.parse(scanData)
      console.log(resData);
      setStartScan(false);
      setData(resData);
    } catch (parseErr) {
      console.error('二维码数据解析失败:', parseErr);
      // 可添加用户提示,告知扫描的二维码格式异常
    }
    setLoadingScan(false);
  }
};

4. 测试特殊数据

提取那2个无法识别的二维码对应的用户数据,用在线工具生成二维码测试:

  • 如果能被react-qr-reader识别,说明是生成参数问题
  • 如果仍不能识别,说明数据中存在特殊字符,需要针对性转义处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:03:01