Toggle navigation
Toggle navigation
This project
Loading...
Sign in
fe
/
yohobuywap-node
·
Commits
Go to a project
GitLab
Go to group
Project
Activity
Files
Commits
Pipelines
0
Builds
0
Graphs
Milestones
Issues
0
Merge Requests
0
Members
Labels
Wiki
Forks
Network
Create a new issue
Download as
Plain Diff
Browse Files
Authored by
毕凯
7 years ago
Commit
dfd944928ed52526fcedec6737507bb7663c170e
2 parents
f029f3cd
fa438322
Merge branch 'feature/limiter' into 'gray'
Feature/limiter See merge request
!1325
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
129 additions
and
39 deletions
.eslintrc
apps/3party/controllers/check.js
config/common.js
doraemon/middleware/error-handler.js
doraemon/middleware/limiter/index.js
doraemon/middleware/limiter/policies/captcha.js
doraemon/middleware/limiter/rules/asynchronous.js
doraemon/middleware/limiter/rules/faker-limit.js
doraemon/middleware/limiter/rules/qps-limit.js
doraemon/views/error/510.hbs
package.json
public/js/global.js
.eslintrc
View file @
dfd9449
{
"extends"
:
"yoho"
,
"parser"
:
"babel-eslint"
,
"parserOptions"
:
{
"sourceType"
:
"module"
},
...
...
@@ -10,4 +11,4 @@
"camelcase"
:
"off"
}
}
\ No newline at end of file
}
...
...
apps/3party/controllers/check.js
View file @
dfd9449
...
...
@@ -59,7 +59,7 @@ exports.submit = (req, res) => {
if
(
geetestRes
)
{
logger
.
info
(
'geetest success'
);
let
remoteIp
=
req
.
get
(
'X-Forwarded-For'
)
||
req
.
i
p
;
let
remoteIp
=
req
.
yoho
.
clientI
p
;
if
(
remoteIp
.
indexOf
(
','
)
>
0
)
{
let
arr
=
remoteIp
.
split
(
','
);
...
...
@@ -67,7 +67,25 @@ exports.submit = (req, res) => {
remoteIp
=
arr
[
0
];
}
let
operations
=
[
cache
.
delAsync
(
`
$
{
config
.
app
}:
limiter
:
$
{
remoteIp
}
`
)];
// pc:limiter:IP 和PC端共用
let
operations
=
[
cache
.
delAsync
(
`
pc
:
limiter
:
$
{
remoteIp
}
`
)];
// 验证码之后一小时之内不再限制qps
if
(
req
.
session
.
apiLimitValidate
)
{
operations
.
push
(
cache
.
setAsync
(
`
$
{
config
.
app
}:
limiter
:
api
:
ishuman
:
$
{
remoteIp
}
`
,
1
,
config
.
LIMITER_IP_TIME
));
}
else
{
operations
.
push
(
cache
.
setAsync
(
`
$
{
config
.
app
}
:
limiter
:
ishuman
:
$
{
remoteIp
}
`
,
1
,
config
.
LIMITER_IP_TIME
));
}
delete
req
.
session
.
apiLimitValidate
;
if
(
req
.
body
.
pid
)
{
let
riskPid
=
decodeURIComponent
(
req
.
body
.
pid
)
+
':'
+
_
.
get
(
req
.
yoho
,
'clientIp'
,
''
);
...
...
config/common.js
View file @
dfd9449
...
...
@@ -160,6 +160,7 @@ module.exports = {
// 100s 最多访问200次
600
:
200
},
LIMITER_IP_TIME
:
3600
,
// 超出访问限制ip限制访问1小时
superCapture
:
'93c70db61fe276f93ce781ad17dc47cd'
,
from
:
from
};
...
...
doraemon/middleware/error-handler.js
View file @
dfd9449
...
...
@@ -4,8 +4,10 @@
*/
const
headerModel
=
require
(
'../models/header'
);
const
logger
=
global
.
yoho
.
logger
;
const
cache
=
global
.
yoho
.
cache
.
master
;
const
helpers
=
global
.
yoho
.
helpers
;
const
sender
=
global
.
yoho
.
apmSender
;
const
config
=
global
.
yoho
.
config
;
const
hostname
=
require
(
'os'
).
hostname
();
const
routeEncode
=
require
(
'./route-encode'
);
const
_
=
require
(
'lodash'
);
...
...
@@ -20,6 +22,51 @@ const forceNoCache = (res) => {
}
};
const
_err510
=
(
req
,
res
,
code
,
err
)
=>
{
res
.
status
(
code
);
if
(
req
.
xhr
)
{
return
res
.
json
({
code
:
err
.
code
,
message
:
'服务器繁忙请稍后重试!'
});
}
return
res
.
render
(
'error/510'
,
{
err
:
err
,
module
:
'common'
,
page
:
'error'
,
title
:
'服务器繁忙 | Yoho!Buy有货 | 潮流购物逛不停'
,
pageHeader
:
headerModel
.
setNav
({
navTitle
:
'服务器繁忙请稍后重试!'
}),
pageFooter
:
true
,
isErr
:
true
});
};
const
_err500
=
(
req
,
res
,
code
,
err
)
=>
{
res
.
status
(
code
);
if
(
req
.
xhr
)
{
return
res
.
json
({
code
:
err
.
code
,
message
:
'服务器错误!'
});
}
return
res
.
render
(
'error/500'
,
{
err
:
err
,
module
:
'common'
,
page
:
'error'
,
title
:
'服务器错误 | Yoho!Buy有货 | 潮流购物逛不停'
,
pageHeader
:
headerModel
.
setNav
({
navTitle
:
'服务器错误!'
}),
pageFooter
:
true
,
isErr
:
true
});
};
exports
.
notFound
=
()
=>
{
return
(
req
,
res
)
=>
{
...
...
@@ -51,11 +98,12 @@ exports.notFound = () => {
* @return {[type]}
*/
exports
.
serverError
=
()
=>
{
return
(
err
,
req
,
res
,
next
)
=>
{
forceNoCache
(
res
);
return
async
(
err
,
req
,
res
,
next
)
=>
{
const
uid
=
req
.
user
?
req
.
user
.
uid
:
0
;
const
udid
=
_
.
get
(
req
,
'cookies.udid'
,
'yoho'
);
forceNoCache
(
res
);
err
.
code
=
err
.
code
||
err
.
statusCode
||
500
;
if
(
req
.
isApmReport
&&
err
.
code
!==
401
)
{
...
...
@@ -63,7 +111,7 @@ exports.serverError = () => {
sender
.
addMessage
({
measurement
:
'error-report'
,
tags
:
{
app
:
global
.
yoho
.
config
.
appName
,
// 应用名称
app
:
config
.
appName
,
// 应用名称
hostname
,
type
:
'server'
,
route
:
`
[
$
{
req
.
method
}]
$
{
_
.
get
(
req
,
'route.path'
,
''
)}
`
,
// 请求路由
...
...
@@ -106,33 +154,45 @@ exports.serverError = () => {
refer
:
req
.
originalUrl
}));
}
}
}
else
if
(
err
.
code
===
9999991
||
err
.
code
===
9999992
)
{
let
remoteIp
=
req
.
yoho
.
clientIp
;
logger
.
error
(
`
error
at
path
:
$
{
req
.
url
}
`
);
logger
.
error
(
err
);
const
isHuman
=
await
cache
.
getAsync
(
`
$
{
config
.
app
}
:
limiter
:
api
:
ishuman
:
$
{
remoteIp
}
`
);
if
(
!
res
.
headersSent
)
{
res
.
status
(
err
.
code
);
if
(
!
isHuman
)
{
if
(
remoteIp
.
indexOf
(
','
)
>
0
)
{
let
arr
=
remoteIp
.
split
(
','
);
if
(
req
.
xhr
)
{
return
res
.
json
({
code
:
err
.
code
,
message
:
'服务器错误!'
remoteIp
=
arr
[
0
];
}
cache
.
setAsync
(
`
$
{
config
.
app
}
:
limiter
:
$
{
remoteIp
}
`
,
1
,
config
.
LIMITER_IP_TIME
);
let
limitAPI
=
helpers
.
urlFormat
(
'/3party/check'
,
{
refer
:
req
.
get
(
'Referer'
)
||
''
});
let
limitPage
=
helpers
.
urlFormat
(
'/3party/check'
,
{
refer
:
req
.
protocol
+
'://'
+
req
.
get
(
'host'
)
+
req
.
originalUrl
});
req
.
session
.
apiLimitValidate
=
true
;
if
(
req
.
xhr
)
{
return
res
.
status
(
510
).
json
({
code
:
err
.
code
,
data
:
{
refer
:
limitAPI
}
});
}
return
res
.
redirect
(
limitPage
);
}
return
res
.
render
(
'error/500'
,
{
err
:
err
,
module
:
'common'
,
page
:
'error'
,
title
:
'服务器错误 | Yoho!Buy有货 | 潮流购物逛不停'
,
pageHeader
:
headerModel
.
setNav
({
navTitle
:
'服务器错误!'
}),
pageFooter
:
true
,
isErr
:
true
});
return
_err510
(
req
,
res
,
510
,
err
);
}
logger
.
error
(
`
error
at
path
:
$
{
req
.
url
}
`
);
logger
.
error
(
err
);
if
(
!
res
.
headersSent
)
{
return
_err500
(
req
,
res
,
err
.
code
,
err
);
}
next
(
err
);
return
next
(
err
);
};
};
...
...
doraemon/middleware/limiter/index.js
View file @
dfd9449
...
...
@@ -70,7 +70,7 @@ module.exports = (req, res, next) => {
// 排除条件:ip白名单/路径白名单/异步请求/登录用户
const
excluded
=
_
.
includes
(
IP_WHITE_LIST
,
remoteIp
)
||
_
.
includes
(
PATH_WHITE_LIST
,
req
.
path
)
||
req
.
xhr
||
!
_
.
isEmpty
(
_
.
get
(
req
,
'user.uid'
));
const
enabled
=
!
_
.
get
(
req
.
app
.
locals
,
'wap.sys.noLimite'
);
const
enabled
=
!
_
.
get
(
req
.
app
.
locals
,
'wap.sys.noLimite
r
'
);
logger
.
debug
(
`
request
remote
ip
:
$
{
remoteIp
};
excluded
:
$
{
excluded
};
enabled
:
$
{
enabled
}
`
);
...
...
doraemon/middleware/limiter/policies/captcha.js
View file @
dfd9449
...
...
@@ -2,6 +2,7 @@
const
helpers
=
global
.
yoho
.
helpers
;
const
_
=
require
(
'lodash'
);
const
WHITE_LIST
=
[
'/3party/check'
,
'/3party/check/submit'
,
...
...
@@ -27,8 +28,7 @@ module.exports = (req, res, next) => {
}
if
(
req
.
xhr
)
{
return
res
.
json
({
code
:
400
,
return
res
.
status
(
510
).
json
({
data
:
{
refer
:
limitAPI
}
});
}
...
...
doraemon/middleware/limiter/rules/asynchronous.js
View file @
dfd9449
...
...
@@ -26,9 +26,9 @@ function isNormalSpider(userAgent) {
module
.
exports
=
(
limiter
,
policy
)
=>
{
const
ua
=
limiter
.
req
.
header
(
'User-Agent'
);
const
synchronizeKey
=
`
wap
:
limiter
:
synchronize
:
$
{
limiter
.
remoteIp
}
`
;
// 同步
const
asynchronousKey
=
`
wap
:
limiter
:
asynchronous
:
$
{
limiter
.
remoteIp
}
`
;
// 异步
const
spiderKey
=
`
wap
:
limiter
:
spider
:
$
{
limiter
.
remoteIp
}
`
;
// 异步
const
synchronizeKey
=
`
pc
:
limiter
:
synchronize
:
$
{
limiter
.
remoteIp
}
`
;
// 同步
const
asynchronousKey
=
`
pc
:
limiter
:
asynchronous
:
$
{
limiter
.
remoteIp
}
`
;
// 异步
const
spiderKey
=
`
pc
:
limiter
:
spider
:
$
{
limiter
.
remoteIp
}
`
;
// 异步
// 正常蜘蛛直接过
if
(
isNormalSpider
(
ua
))
{
...
...
doraemon/middleware/limiter/rules/faker-limit.js
View file @
dfd9449
...
...
@@ -9,7 +9,7 @@ module.exports = (limiter, policy) => {
res
=
limiter
.
res
,
next
=
limiter
.
next
;
// eslint-disable-line
const
key
=
`
wap
:
limiter
:
faker
:
$
{
limiter
.
remoteIp
}
`
;
const
key
=
`
pc
:
limiter
:
faker
:
$
{
limiter
.
remoteIp
}
`
;
if
(
req
.
header
(
'X-Requested-With'
)
===
'XMLHttpRequest'
)
{
cache
.
decrAsync
(
key
,
1
);
...
...
doraemon/middleware/limiter/rules/qps-limit.js
View file @
dfd9449
...
...
@@ -10,9 +10,6 @@ const cache = global.yoho.cache.master;
const
config
=
global
.
yoho
.
config
;
const
_
=
require
(
'lodash'
);
// 超出访问限制ip限制访问1小时
const
limiterIpTime
=
3600
;
// 页面访问限制
const
MAX_TIMES
=
config
.
REQUEST_LIMIT
;
...
...
@@ -27,12 +24,18 @@ module.exports = (limiter, policy) => {
getOp
[
key
]
=
cache
.
getAsync
(
ruleKeys
[
key
]);
});
getOp
.
human
=
cache
.
getAsync
(
`
$
{
config
.
app
}
:
limiter
:
ishuman
:
$
{
limiter
.
remoteIp
}
`
);
return
Promise
.
props
(
getOp
).
then
((
results
)
=>
{
logger
.
debug
(
MAX_TIMES
);
logger
.
debug
(
_
.
values
(
ruleKeys
));
logger
.
debug
(
results
);
if
(
results
.
human
)
{
// 经过验证码之后1小时有效期内不再验证qps
return
Promise
.
resolve
(
true
);
}
// 遍历限制规则,若满足返回相应处理策略, 否则页面访问次数加1
let
operation
=
[];
...
...
@@ -42,9 +45,10 @@ module.exports = (limiter, policy) => {
if
(
!
results
[
key
])
{
operation
.
push
(
cache
.
setAsync
(
cacheKey
,
1
,
+
key
));
}
else
if
(
+
results
[
key
]
>
+
val
)
{
logger
.
warn
(
`
pc
:
limiter
:
$
{
limiter
.
remoteIp
}
`
);
// ip限制1小时
operation
.
push
(
cache
.
setAsync
(
`
pc
:
limiter
:
$
{
limiter
.
remoteIp
}
`
,
1
,
limiterIpTime
));
operation
.
push
(
cache
.
setAsync
(
`
pc
:
limiter
:
$
{
limiter
.
remoteIp
}
`
,
1
,
config
.
LIMITER_IP_TIME
));
return
Promise
.
resolve
(
policy
);
}
else
{
operation
.
push
(
cache
.
incrAsync
(
cacheKey
,
1
));
...
...
doraemon/views/error/510.hbs
0 → 100644
View file @
dfd9449
<div
class=
"err-page yoho-page"
>
<div
class=
"err-bg"
></div>
</div>
...
...
package.json
View file @
dfd9449
...
...
@@ -74,13 +74,14 @@
"xml2js"
:
"^0.4.19"
,
"yoho-express-session"
:
"^2.0.0"
,
"yoho-md5"
:
"^2.0.0"
,
"yoho-node-lib"
:
"=0.6.
2
"
,
"yoho-node-lib"
:
"=0.6.
5
"
,
"yoho-zookeeper"
:
"^1.0.9"
},
"devDependencies"
:
{
"@mapbox/stylelint-processor-arbitrary-tags"
:
"^0.2.0"
,
"autoprefixer"
:
"^7.2.4"
,
"babel-core"
:
"^6.26.0"
,
"babel-eslint"
:
"^8.2.2"
,
"babel-loader"
:
"^7.1.2"
,
"babel-plugin-transform-runtime"
:
"^6.23.0"
,
"babel-preset-env"
:
"^1.6.0"
,
...
...
public/js/global.js
View file @
dfd9449
...
...
@@ -49,6 +49,8 @@ $(document).ajaxError((event, xhr) => {
window
.
location
.
href
=
`
/
signin
.
html
?
refer
=
$
{
encodeURIComponent
(
window
.
location
.
href
)}
`
;
}
}
}
else
if
(
xhr
.
status
===
510
&&
xhr
.
responseJSON
.
data
&&
xhr
.
responseJSON
.
data
.
refer
)
{
window
.
location
.
href
=
xhr
.
responseJSON
.
data
.
refer
;
}
else
if
(
xhr
.
status
===
403
&&
xhr
.
responseJSON
.
code
===
4403
)
{
tip
.
show
(
xhr
.
responseJSON
.
message
);
setTimeout
(
function
()
{
...
...
Please
register
or
login
to post a comment