‘开发那些事儿’ 分类下的所有文章
2017三月15

手工统计新粉为何会算多

开发遇到的问题 评论关闭

进线的新粉分为3类,

  1. 纯新粉(正是我们要想要统计的)
  2. 重叠新粉,指新粉已添加了其他客服的微信,又添加了当前客服的微信
  3. 老粉重进,指被删除的老粉又重新添加,微信会不定时将删除的老粉以新粉状态推送出来。

针对第2种与第3种情况,客服人员很难识别出来,在统计新粉的时候会加进去,必然造成新粉多算。
而A9微信通以独创的身份识别技术,从根源上消灭了第2种与第3种情况,保证统计的新粉是精准的。

 
2015七月10

一次神奇的问题解决

开发遇到的问题 评论关闭

问题:SQLServer偶发性连接不上:在客户端执行sql语句,时不时的执行不了,报用户名密码错误。
解决历程:
1,重装服务器,重装SQLSERVER 不能解决!
2,在网络上找各种解决方案,baidu,google,bing, stackoverflow各种方案尝试一遍,仍无解。
3,对着服务器烧香拜佛,服务器不鸟
最后解决:将服务器双网卡禁掉了一个,可以了!!!!

2014八月21

ASP:Image控件生成的代码自动增加border-width:0px的Bug处理

开发遇到的问题 评论关闭

在用ImageButton时,前台生成的控件会自动带上element.style{border-width:0px} 影响其他样式。
这个是ASP.NET的一个Bug,需要实现自己的类解决
using System;
using System.Web.UI.WebControls;

public class BorderlessImageButton : ImageButton {
public override Unit BorderWidth {
get {
if (base.BorderWidth.IsEmpty) return Unit.Pixel(0);
else return base.BorderWidth;
}
set {
base.BorderWidth = value;
}
}
}

然后不使用ImageButton,而是使用BorderlessImageButton
或者直接在web.config增加映射关系。



tagMapping>
pages>
system.web>

参考:Remove border-width:0px from asp:Image or asp:ImageButton

http://weblogs.asp.net/reganschroder/remove-border-width-0px-from-asp-image-or-asp-imagebutton

2014八月2

链接服务器的使用

开发遇到的问题 评论关闭

链接服务器配置简答,操作方便,是进行数据处理很有用的工具。
但若在存储过程中使用了链接服务器,就要注意:
若链接服务器挂了,则对应的存储过程在执行时都会阻塞,阻塞时间就是链接服务器的超时时间,会影响系统的使用。
所以使用链接服务器的场合是:
1,涉及到链接服务器的存储过程独立,不与其他逻辑混在一起,sp短小精悍
2,设置链接服务器的超时时间,若在局域网内,设置成6s超时就够用。

2013八月29

存储过程使用场合

设计好的思路 评论关闭

使用存储过程的前提:
1,没有移植的问题,比如做的是一产品,客户要求不同的数据库,这时将逻辑放到存储过程上就不好移值,放到代码中则好很多。
2,项目规模比较小,如几千人使用的企业级系统,很少考虑复杂的分库分表分服务器

最佳策略:尽量不用存储过程

在规模小时,如几千人使用的企业级系统:
方案:
对于简单的查询,尽量不用存储过程,联合表可用视图,这样做的好处有二:
1,用视图分页的话可以通过底层框架生成通用的分页,而用存储过程需要对每个sql写rownumer之类
2,用视图页面可通过代码生成工具很容易直接生成,开发效率高。
对于复杂的查询或者事务更新可以使用存储过程,一是利用存储过程预编译的特点提高效率,并且逻辑都在数据库里,避免了多次查询。二是更改逻辑比较方便,不用打开项目,修改再部署,并且动到了bin的话,还会引起系统重新编译。(当然第二种好处适合小项目,对稳定性要求不高,不会因改错了一个逻辑,耽搁5分钟就会有大量投诉。)

参考:大型系统必须得要存储过程和触发器吗?

2013六月27

质量保证方式

1,测试
2,监控
3,预案建立,防止问题出现时思维混乱
出现问题时想彻底解决方案!杜绝再次发生。
对于技术,如网站与系统,关键就是做好三点,速度、稳定性、安全性
安全性:可能发生的一定会发生
1,学好攻,做检测
2,做好防,服务器限制IP访问,策略,权限,默认端口,账号更改(sa,administrator)
3,做好预警,异常系统登陆日志,异常数据库连接,服务器新文件添加

关于监控,对于功能来说,核心功能在上线后要做好数据统计,分析是否有异常数据产生。
如一次上线积分产品,功能完成后,基本数据未修改,造成本不是积分产品的产品当成积分产品下,造成损失!

上线阶段:
1,开发:代码审查与TDD测试
2,上线:eventvwr分析与IIS日志
3,上线后:总结

对于新的项目流程
1,确定流程图
2,画出原型图
3,开发,代码审核与TDD
4,上线
5, 定期召集开会,看现有什么问题,改进【监控】

2013五月23

Could not load file or assembly (Exception from HRESULT: 0×80131040)

开发遇到的问题 评论关闭

编译出现这个错误:
Could not load file or assembly 'Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0×80131040)

操作:使用微软企业库,修改了Microsoft.Practices.EnterpriseLibrary.Common.dll,Microsoft.Practices.EnterpriseLibrary.Data.dll
(一个知识点是修改了这种dll后,微软的强签名就没了,由PublicKeyToken=31bf3856ad364e35变成了PublicKeyToken=null)

问题引发场景:
新项目中引用了修改的企业库Common.dll,Data.dll,未改的企业库Caching.dll,问题就来了:
微软的企业库Caching.dll里面还是引用原来的带有强签名的Common.dll(可通过Reflector查看此引用),而我们在这个新项目中引用的是自己修改的Common.dll,在编译时造成Caching.dll找不到微软的Common.dll,从而引发上述错误。
解决方法:
1,修改Caching.dll,将其引用的Common.dll改为自已修改后的Common.dll
2,因本项目中没有用到Caching.dll的地方,去掉此Caching.dll,解决问题
3,因微软的Common.dll是强签名,可注册到GAC全局

注:
1,引用Common.dll的微软企业库还有
Microsoft.Practices.EnterpriseLibrary.Caching.Cryptography.dll
Microsoft.Practices.EnterpriseLibrary.Caching.Database.dll
Microsoft.Practices.EnterpriseLibrary.Caching.dll
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll
2,一个被忽略的基本事实是:打包的dll如father.dll 里面引用了son.dll,那么在新项目中若引用father.dll,那么在bin下也要有son.dll的存在。

2013一月28

iframe嵌套session失效问题

开发遇到的问题 评论关闭

起因:
IE6/IE7从安全性角度考虑,
支持的P3P(Platform for Privacy Preferences Project (P3P) specification)协议默认阻止第三方无隐私安全声明的cookie,firefox,chrome无此问题。
即在IE6/IE7下,嵌入的页面若与主页面域不同,则嵌入页的cookie不能被主域读取,也就意味着保存在cookie中的sessionid是没有的,在上传服务器时,因没有传sessionid,服务器是读取不了已经创建的session中的内容。
解决方案:
第1种:

> 打开IIS管理器 inetmgr
> 选择被嵌入iframe源站点或者目录,右键点击打开属性框 
> 切换到HTTP头 
> 添加 
> 自定义HTTP头名: P3P
> 自定义HTTP头值: CP="CAO PSA OUR"
> 关闭属性框退出,即刻生效

第2种:
在被嵌入页面page_onload里添加一语句:Response.AddHeader("P3P","CP=CAO PSA OUR");

2013一月27

BASE64 VLQ 编码规则

好的代码 评论关闭

VLQ 是 Variable-length quantity 的缩写,是一种通用的,使用任意位数的二进制来表示一个任意大的数字的一种编码方式。这个编码方式是在 MIDI 文件格式中定义的,用来节省空间

线编码解码的网站:http://murzwin.com/base64vlq.html ,
开源库相关实现:
https://github.com/mozilla/source-map/blob/master/lib/source-map/base64-vlq.js,

首先我们先来了解下 VLQ 是什么,VLQ 是 Variable-length quantity 的缩写,是一种通用的,使用任意位数的二进制来表示一个任意大的数字的一种编码方式。这个编码方式是在 MIDI 文件格式中定义的,用来节省空间。在其他地方也有很多类似这样的编码格式,比如在 Google’s protocol buffers 中,还有我们马上要讨论到的 BASE64 VLQ 中。想了解的更多,请参考wikipedia

我们先来看看 MIDI 中的 VLQ 编码是如何编码 137 这个数字的吧:(摘抄自 wikipedia)

  • 先把 137 转换成二进制:10001001
  • 7 bit 一组,把二进制分开,不足的补 0 ,变成 0000001 0001001
  • 把最低的7位拿出来,在最高位补0表示最后一位,变成 0000 1001,这个作为最低位,放在最后边。
  • 在其他组的最高位补 1 ,表示没有结束,后面跟着还有数据。在这里就是 1000 0001
  • 拼在一起,就变成了 1000 0001 0000 1001 .

这就是 VLQ 的变化过程。

那么什么是 Base64 VLQ 呢?和上面的变换过程有什么区别呢?

我们可以先来参考我博客的另外一篇文章,先来回顾下 Base64 编码:BASE64 编码规则

我们可以看到 Base64 是一种可以把二进制数据编码成用 ASCII 表示的一种编码规则,但是受限于 Base64 采用的字符集,一个 Base64 字符只能表示 6bit 的数据。所以上面的 VLQ 中 7 bit 一组的分组方式,在这里就要变成 5 bit 一组的分组了。

另外,Base64 VLQ 需要能够表示负数,于是规定了需要先把数字变成无符号数,用最后一位来作为符号标志位。我们直接来做一个变换吧,这样理解的最快。在例子中可以看到和上面的 VLQ 编码还是有一定差别的。

不妨还拿 137 来做示例吧。

  • 先把 137 转换成二进制:10001001
  • 由于 137 是正数,所以在最低位补0 变成 100010010
  • 按照 5bit 一组的方式分组,变成 01000 10010
  • 按照从低位到高位的顺序,以 5bit 一组为单位,依次拿出数据做转换。
  • 先拿出第一组 10010 , 因为后面还有数据,所以需要在高位补 1,变成 110010 ,编码成 Base64: y
  • 再拿出第二组,也是我们这里的最后一组,01000 , 由于是最后一组,所以在高位补 0 变成 001000,编码成 Base64: I
  • 按照从低位到高位的顺序把这些 ASCII 字符拼接起来,变成 yI

可以看到在 VLQ 中,编码顺序是从高位到低位,在 Base64 VLQ 中,编码顺序是从低位到高位。

那么如何解码呢?相信了解了编码过程后,解码过程就不必再讲解了。

参考:http://blog.allenm.me/2012/12/base64-vlq-encoding/

http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html

2013一月26

跨域问题

同一域:指协议、域名,端口号都相同,否则为跨域。
表现为:如在a.com/index.html 利用iframe引用了b.com/index.html,
那么:在a.com/index.html无法更改b.com/index.html的对象,如dom,css等,但是可读取的。即只读
反之,在b.com/index.html中对a.com/index.html也是只读的。
//在b.com/index.html中可用document.referrer来引用a.com/index.html的网址
不过,可在a.com/index.html利用对b.com/index.html的访问权限,在b.com中创建一对象,此对象在a.com中是可以操作的。

对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。
具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。当然这种办法只能解决主域相同而二级域名不同的情况

引用:http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

2013一月19

网站并发数

开发遇到的问题 评论关闭

浏览器对同一个域名访问的并发数是有限制的,同一时间下,如下表:

浏览器 并发数
IE 6,7 2
IE 8 6
Firefox 2 2
Firefox 3 6
Safari 3,4 4
Chrome 1,2 6
Chrome 3 4
Chrome 4+ 6
iPhone 2 4
iPhone 3 6
iPhone 4 4
Opera 9.63,10.00alpha 4
Opera 10.51+ 8

因为浏览器只对单个域名限制并发数,而不对单个IP限制并发数,所以可将一个IP地址映射到多个域名,然后使用这些域名访问网站资源,这样原本浏览器的并发数为6,使用两个域名并发数就可以达到12个了。但需要注意的是,域名并不是越多就越好的,因为域名解析也需要花费时间,而且并发数太多也会耗费客户端太多的CPU,域名数量到了一定程度,网页性能就会开始下降,所以在应用中需要根据实际情况寻找一个平衡点。如果不是特别需要,一般24个为佳。

2012十一月15

多状态一字段存储

设计好的思路 评论关闭
--多状态一字段存储,避免增加状态需要再新增字段的事情。sqlserver中set值即是类似存储
--创建状态表,用二进制上的1标识是否,生成身份值在建立表是指定,据身份值取状态,只需进行与运算即可
--可扩大,比如8进制,每位上可有8个选择,--假如有7种状态,则可用一个字段标识出56种选择
DROP TABLE #MyStatus
GO

CREATE TABLE #MyStatus( StatusName NVARCHAR(100),StatusValue INT )
INSERT INTO #MyStatus
VALUES('是否高',1) --1,001 二进制数位
INSERT INTO #MyStatus
VALUES('是否富',2) --2,010
INSERT INTO #MyStatus
VALUES('是否帅',4) --4,100

SELECT *
FROM #MyStatus

--生成身份值
--张三
WITH zhangsan AS(
	SELECT '是否高' StatusName,1 StatusValue
	UNION SELECT '是否富' StatusName,0 StatusValue
	UNION SELECT '是否帅' StatusName,1 StatusValue
)
SELECT SUM(m.StatusValue) 张三身份值
FROM zhangsan z
JOIN #MyStatus m ON z.StatusName = m.StatusName
WHERE Z.StatusValue = 1

--据身份值取出状态,李四身份值为3,查询各状态
SELECT m.StatusName,
CASE WHEN m.StatusValue & 3 = m.StatusValue THEN '是'
ELSE '否' END
FROM #MyStatus m
2012十月18

xml文件utf-8 code读取乱码解决

开发遇到的问题 评论关闭

1,将编码格式 encoding="utf-8"指定去掉
2,用记事本打开xml,另存为unicode解决。

2012六月25

ViewStateException: Invalid viewstate.

开发遇到的问题 评论关闭

错误明细:
详细错误:
System.Web.UI.ViewStateException: Invalid viewstate. Client IP: 192.168.21.184 Port: 1418 Referer: http://192.168.16.55:888/Increment/PersonalCustomer.aspx?type=developcall&MenuID=508&menuname=发展部客户跟进 Path: /Increment/PersonalCustomer.aspx User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) ViewState: /wEPDwUJMzIwOTI4NzM3D2QWAgIBD2QWAgIBDw8WAh4EVGV4dAVJ57O757uf5bey6Ieq5Yqo6YCa55+l5oqA5pyv6YOo5aSE55CGLOivt+eojeWQjuiuv+mXriEgIC0tMjAxMi0wNi0yNSAwODoyOGRkZP1AV1Xh2GYIxvsOtpTpoN+mHmQzbqafkrv3eZ/waeQN,/wEPDwUJMzIwOTI4NzM3D2QWAgIBD2QWAgIBDw8WAh4EVGV4dAVJ57O757uf5bey6Ieq5Yqo6YCa55+l5oqA5pyv6YOo5aSE55CGLOivt+eojeWQjuiuv+mXriEgIC0tMjAxMi0wNi0yNSAwODoyOGRkZP1AV1Xh2GYIxvsOtpTpoN+mHmQzbqafkrv3eZ/waeQN,/wEPDwUKMTg1MDQyMjI5Nw9kFgICAw9kFgICAw9kFgJmD2QWDgIHDxBkEBUHDOivt+mAieaLqS4uLg/mlrDlrqLmiLfotYTmlpkKQeexu+WuouaItwpC57G75a6i5oi3CkPnsbvlrqLmiLcKROexu+WuouaItwzlj5bmtojorqLljZUVBwAOYXV0b2Rpc3RyaWJ1dGUJc3Ryb25nYnV5CWludGVuZGJ1eQh0aGlua2J1eQdpc3ZhbGlkBmNhbmNlbBQrAwdnZ2dnZ2dnZGQCCQ8QZGQWAGQCDQ8QZBAVCwotLeaJgOaciS0tCeaXoOS6uuaOpQnp… —> System.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or a non-white space character among the padding characters.

原因:页面中含有多个_VIEWSTATE引起,导致此错误。
解决方法:禁用某一页面的viewstate.
 方法:1)page上加EnableViewState="false" 2)去掉form的runat=server

2012五月3

js文件中动态加载js文件

js文件中动态加载js文件
因加载顺序不同,在加载js文件时,要动态传的变量还未进行初始化,故参数传不进,
方法是利用ajax异步加载

var IsLoadFieOk = false;//是否已完成js文件的加载
var CallServerIP  = "192.168.19.157";

LoadJSfile("scrjquery", "http://"+CallServerIP + "/interface/js/jquery-1.3.2.min.js");
LoadJSfile( "scrDailOut", "http://"+CallServerIP + "/interface/2.js");

function LoadJSfile(sID,url) {
    IsLoadFieOk = false;
    AjaxPage(sID,url);
    var i = 0;
    while (!IsLoadFieOk && i++<2000) {} //保证异步加载的文件能够做到顺序加载
}

function AjaxPage(sId, url){
    var oXmlHttp = GetHttpRequest() ;

    oXmlHttp.OnReadyStateChange = function()  

    {

        if ( oXmlHttp.readyState == 4 )

        {

            if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 )

            {

                IncludeJS( sId, url, oXmlHttp.responseText );
                //alert(url);

            }

            else

            {
                alert( 'XML request error: ' + oXmlHttp.statusText + ' (' + oXmlHttp.status + ')' ) ;

            }

        }

    }

    oXmlHttp.open('GET', url, true);

    oXmlHttp.send(null);
    //return "hello";

}

同时若ajax要跨域访问数据,那么将Internet选项-安全- Internet,受信任的站点中的通过域访问数据资源打开。

2012四月1

MsSql限制IP所引发的失误

开发遇到的问题 评论关闭

现需要限制MsSql上的登录IP,错误的直接将以下语句执行,而没有改192.168.1.1,此时连接服务器就再也连接不上,需要用DAC解决
注:限制IP访问最好用IPsec策略做,以免影响性能。


1,失误代码

USE master

GO

CREATE TRIGGER tr_LoginCheck

ON ALL SERVER

FOR LOGON

AS

DECLARE @ClientHost varchar(100)

SET @ClientHost= EVENTDATA().value(‘(/EVENT_INSTANCE/ClientHost)[1]‘, ‘varchar(15)’)

IF ClientHost <>’127.0.0.1′ AND ClientHost <> ‘<local machine>’

ROLLBACK TRAN

GO

–此触发器可在[服务器对象 - 触发器下]查看

可能要给账号开权限

USE [master]
GO
CREATE USER [myuser] FOR LOGIN [myuser]
GO
–grant select on ipcheck to myuser
 
grant VIEW SERVER STATE to myuser
 

2,失误后登录提示:login failed due to a TRIGGER

3,解决方案:

开始-运行-cmd: sqlcmd -S LocalHost -d master -A

1> DROP TRIGGER tr_LoginCheck ON ALL SERVER

2> GO

2012三月15

EMS包裹信息抓取

公司每天EMS包裹单有很多,人工查效率不高且易出错,想用程序上传包裹单查询,考察了市面上的程序,kuaidi100不错,经沟通,并不支持EMS,他们是免费的,EMS开放的话服务器会抗不住,自己写!
实现过程:
1,利用AspriseOCR进行验证码识别。
2,将获取的验证码构造Post数据上传。
3,对于反应的包裹消息源页面,用Winista.HtmlParser分析出包裹信息。
4,源码:enjoytools/…

2012一月12

web.config中poolsize与mssql中的connection

开发遇到的问题 评论关闭

web.config中的 max poolsize指的是保存的与数据库连接的个数,由.net维护,常报的“超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。 ”指的是连接数超出了max pool size引起。
连接池中的连接与mssql中的sys.dm_exec_connections中是对应的,不过sys.dm_exec_connections的连接也包含其他连接,故总数是>=pool size中的连接数量的。
可以在sys.dm_exec_connections中通过web.config连接的用户名来查询目前web.config连接了多少个:
SELECT a.most_recent_sql_handle,COUNT(1) d FROM
sys.dm_exec_connections a
JOIN sys.dm_exec_sessions b ON a.session_id = b.session_id AND b.login_name=’brm’
GROUP BY a.most_recent_sql_handle
ORDER BY d DESC

2012一月10

死循环引起的连接池耗尽

开发遇到的问题 评论关闭
用户反应系统响应慢,报连接池超过最大连接数错误,上去看服务器,CPU,内存都很正常。过一段时间系统又自动恢复。通过以下方法排查连接数:
sp_configure ‘user connections’
—-查看系统连接数:
SELECT d.name,b.login_name,COUNT(1) ccount,m.text  FROM
sys.dm_exec_connections a
JOIN sys.dm_exec_sessions b ON a.session_id = b.session_id –AND b.login_name IN('OA','brm')
JOIN sys.databases d ON b.database_id = d.database_id
cross apply  sys.dm_exec_sql_text(a.most_recent_sql_handle)m
GROUP BY d.name,b.login_name,m.text
ORDER BY d.name,b.login_name,ccount DESC

—-或者看明细

SELECT b.session_id,d.name,b.login_name,m.text,
a.client_net_address,a.connect_time,a.last_read,a.last_write
FROM sys.dm_exec_connections a
JOIN sys.dm_exec_sessions b ON a.session_id = b.session_id –AND b.login_name IN('OA','brm')
JOIN sys.databases d ON b.database_id = d.database_id
cross apply  sys.dm_exec_sql_text(a.most_recent_sql_handle)m
where client_net_address != '<local machine>'
order by a.last_read desc

 
发现排在第一位的连接数景有数千,意味着一个会话内发生了上千次的连接,这是很异常的,分析sql语句来源定位异常sql语句:
SELECT * FROM sys.dm_exec_sql_text(0x03000600B1C9EA687B3F2801CA9F00000100000000000000)
–看sql语句
SELECT TOP 50
qs.total_worker_time/qs.execution_count/1000. as [平均消耗CPU 时间(ms)],
total_worker_time/1000 AS [总消耗CPU 时间(ms)],execution_count [运行次数],
SUBSTRING(qt.text,qs.statement_start_offset/2+1,
(case when qs.statement_end_offset = -1
then DATALENGTH(qt.text)
else qs.statement_end_offset end -qs.statement_start_offset)/2 + 1)
as [查询语句], qt.text [所在存储过程],
qt.dbid, dbname=db_name(qt.dbid),
qt.objectid,object_name(qt.objectid,qt.dbid) ObjectName
FROM sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(qs.sql_handle) as qt
WHERE qs.last_execution_time >=’2012-01-10 10:00′ AND dbid = 6
AND qs.sql_handle = ’0x03000600B1C9EA687B3F2801CA9F00000100000000000000′
发现最大连接数为596,599?
2011十一月14

sqlserver用IP连接不上

开发遇到的问题 评论关闭

外呼系统连接数据库, 数据库服务器的配置都已OK,但用IP就是连接不上,换用电脑名/服务 解决.
TA\SQL2005