在使用golang实现OAuth2授权码方式时,报错:(error) ERR Protocol error: invalid bulk length。经逐步排查,并借助Redis Monitor命令,发现是redis使用出现了问题,报错指令格式为hmset a a1 "" a2 "hello",因value为空导致报错。

代码在本地测试时,连接的是本地的redis,localhost:6379,当执行hmset a a1 "" a2 "hello",不会报错,可正常写入redis;
代码部署后,连接的是redis cluster的proxy,地址为代理的ip:host,当执行hmset a a1 "" a2 "hello",就会报错。
初步猜测是redis cluster版和单机版不同导致value为空报错,试验了通过命令"redis-cli -c -a 密码 -h 地址 -p 端口"连接redis cluster,而不是cluster的proxy,发现不会报错,也可正常写入redis。遂定位问题出现在proxy处。通过查看源码,发现有这么一处(见代码所示),猜测是proxy层做了预处理。

  /* Try to determine the bulk length by parsing the number
                 * after the '$' char. */
                if (arglen == REQ_STATUS_UNKNOWN) {
                    if (*p != '$') {
                        proxyLogErr("Failed to parse multibulk query for "
                                    "request " REQID_PRINTF_FMT  ": '$' not "
                                    "found!", REQID_PRINTF_ARG(req));
                        if (err) {
                            *err = sdscatprintf(sdsempty(),
                                "Protocol error: expected '$', got '%c'", *p);
                        }
                        status = PARSE_STATUS_ERROR;
                        goto cleanup;
                    }
                    /* Search the '\r' at the end of the bulk line and
                     * advance the pointer from 1 position from '$'. */
                    nl = strchr(++p, '\r');
                    if (nl == NULL) {
                        status = PARSE_STATUS_INCOMPLETE;
                        goto cleanup;
                    }
                    len = nl - p;
                    if (line != NULL) sdsfree(line);
                    line = sdsnewlen(p, len);
                    char *errptr = NULL;
                    arglen = strtoll(line, &errptr, 10);
                    if (arglen <= 0 || (errptr && errptr < (line + len))) {
                        if (err) {
                            *err =
                                sdsnew("Protocol error: invalid bulk length");
                        }
                        status = PARSE_STATUS_ERROR;
                        goto cleanup;
                    }
                    req->current_bulk_length = arglen;
                    /* Increment the query offset by the bulk length + 3,
                     * since it still was pointing to '$', so '$' + '\r\n'
                     * is three bytes. */
                    req->query_offset += (len + 3);
                    if (req->query_offset >= buflen) {
                        status = PARSE_STATUS_INCOMPLETE;
                        goto cleanup;
                    }
                    p = req->buffer + req->query_offset;
                }

 分别连接redis cluster 的proxy、redis cluster、redis单机版,进行测试如下:

连接proxy:
> hmset a a1 "" a2 "hello"
(error) ERR Protocol error: invalid bulk length
> set "" ""
(error) ERR Protocol error: invalid bulk length
>set a null
OK
>set a ""
(error) ERR Protocol error: invalid bulk length

连接redis cluster:
> hmset a a1 "" a2 "hello"
OK
> set "" ""
OK
>set a null
OK
>set a ""
OK

连接redis单机版:
> hmset a a1 "" a2 "hello"
OK
> set "" ""
OK
>set a null
OK
>set a ""
OK

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐