Problem overview
Today, for the first time in the Nginx+lua architecture, I wrote a background interface that requires the operation of Redis, which is primarily to accept post requests from the client in JSON format, to insert, delete, query, and so on for tasks saved in Redis. Although Nginx,lua and so are just contact, but these interfaces or downwind of the times to sit down, can not forget to thank Chungo also spring.
The tasks recorded in Redis are simple, with each task being inserted, a hash structure is added to the Redis, each time the query returns each field of the set and the corresponding value value, such as Md5,filesize. Because the task type is different, some field may not exist in the task, and the field should not be displayed when the query results are returned in JSON format.
Take the MD5 domain as an example, after the current task in the MD5 domain execution hget, should be a judgment on the return results, if the hash structure is not set MD5 this field, then skip, continue to execute the subsequent logic, if the MD5 field is set, then the value of the field is removed, inserted into the result table , which is then returned as part of the result in JSON format, back to the background.
Test, it is found that when some fields are not set, the query results will still return the field to the query caller, but its value part is null. For example, execute the following test case:
Curl-d "{\"queryfile\ ":[{\"url\ ":\"/ Www.baidu.com/img/bdlogo.gif\ "}]}" "127.0.0.1/cjson"
Although for this task, the MD5 field is not set when you insert it, but the returned result contains the MD5 field:
{"result":[{"URL":"\/www.baidu.com\/img\/bdlogo.gif", "result":0 , "MD5":null, "putflag":"Remote"}]}
Problem analysis
To see this, the first thought of course is that the Lua script does not invalidate the return value of the Hget MD5 operation, which I wrote for the first time:
local md5,err=red:hget (tasklist,"MD5"ifand"then End
From the following results, when the MD5 value is empty, the judging condition does not filter it out and still executes the TB.MD5=MD5. Because the Redis module is also called Spring Brother Lua-resty-redis, so guess whether Chun brother to the Redis query results null value with a "null" string returned, so the above lines of code to change:
local md5,err=red:hget (tasklist,"MD5"if and MD5 ~= "null Then End
Still filtering failed, suddenly bright, found that the query results show "MD5": null, rather than "MD5": "null", the above speculation is not.
Red:hget (tasklist, "MD5") must have returned a null-related result, but the result is either nil, not an empty string, or "null". Again, the value type may not be a string, although this guess looks strange because the type is indeed a string when MD5 is set. Then, in front of the judgment statement, add a sentence to print the message:
Ngx.say ("type of NULL is": Type(MD5))
Sure enough, this "null" is not a string type, but a userdata type, and the UserData type is certainly not equal to the string type, so the above filter will not take effect regardless of what is set, and will always execute tb.md5=md5.
This is the reason for finding it, but it hasn't been resolved yet. Since when the hget operation returns a null value, Lua-resty-redis sets it to a userdata type, how do we filter the case in the code? The essential problem is, red:hget when the query Resdis result is empty, what exactly is returned? (Not NULL, is string)
This time the benefits of open source is reflected, in the Https://github.com/agentzh/lua-resty-redis swept the next Redis.lua file, found that the return is ngx.null.
Well, the problem is solved, change the filter code above to:
local md5,err=red:hget (tasklist,"MD5"ifandnull and MD5 ~= NGX . NULL Then End
You can guarantee that the returned result will not contain a field with a value of NULL.
Above his business
Looking back at the Lua-resty-redis document, found about the above content, in the readme has been written clearly, in https://github.com/agentzh/lua-resty-redis/blob/master/ Readme.markdown, there is a sentence:
A non-nil Redis "bulk reply" results in a Lua string as the return value. A nil bulk reply results in a ngx.null return value.
First of all should not be self-reproach, but once again praise Agentzh attitude, industry benchmark.
What is Ngx.null?
So what exactly is Ngx.null? The Http://wiki.nginx.org/HttpLuaModule has the following instructions:
The Ngx.null constant is a null light userdata usually used to represent nil values in Lua tables etc and are similar to th E Lua-cjson library ' s Cjson.null constant. This constant is first introduced in the V0.5.0RC5 release.
Ngx.null in print, Ngx.print, Ngx.log, Ngx.say and other functions, has the following characteristics:
LUA nil arguments is accepted and result in literal "nil" strings when Lua Booleans result in literal "true" or "false" Strings. And the ngx.null constant would yield the "null" string output.
Why are you designing this?
Lua-resty-redis, why would you return a userdata type of ngx.null if the Redis query is empty? Straight back to nil, okay?
The answer is no, because nil has a special meaning in Lua, and if a variable is set to nil, it is tantamount to saying that the variable is undefined, just like any other undefined variable that is infinite. Then, if you set the result of Redis query null to nil, you cannot differentiate between "query is empty" and "undefined", for example, in a table, a key corresponds to a value, and if the value is set to nil, it is obviously unreasonable to make key disappear out of thin air. So a unique value of a UserData type must be used to indicate that the query is empty, but not the same as undefined variables, such as Ngx.null. The same situation must be seen in the SQL LUA module to handle the case where the key value query in the record is empty.
Ghostly nil.
This is about the magic nil in Lua. Nil is a type that has only one value, which is also called Nil. The value of the change has only one function, indicating that a variable does not exist. Unlike conventional languages like C\c++, "No" is empty, and 0 is completely two concepts. In C, if a string is empty, then it has only a \nul terminator of 0, which is false if the alignment is logically judged.
But in Lua, as long as a variable is not a nil type or false in a Boolean, it is logically judged, and the result is true, even if the value is a number 0, or an empty string.
Nil, NULL, and Ngx.null