web服务(同域和跨域)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web服务(同域和跨域)相关的知识,希望对你有一定的参考价值。
参考技术A注: 使用XMLHttpRequest获取数据的模式也成为Ajax
当应用所在同一个域托管数据时,XMLHttpRequest是为应用获取数据的一种好的方法。当为第三方获取数据,需要用到JSONP(JSON with Padding)
Web服务允许你指定一个回调函数。指定URL时,在末尾增加一个参数,就像这样
当心浏览器缓存,大多数浏览器都有一个有趣的特性,如果你反复获取同一个URL,浏览器为了提高效率会把它缓存起来,所以你会反复的得到同样的缓存文件。解决方法如下:
如果让网页实时刷新的话,就要设置一个定时器,可以设置每3秒请求一次网络数据。如果这样的话,需要每三秒就向服务器发一个<script src=url></script>来请求数据。就要把html中的<script>删除,在javascript中实时创建。
当实时请求数据时,就有可能请求重复数据,怎么来去除重复数据在页面的显示呢?这就用到了增量更新。设置一个lastReportTime的变量,每次请求数据时,把最后一条最新的时间传给这个变量,并且把这个变量传给服务器,来获取这个时间段以后的数据,这样就可以防止有重复数据啦。
知行办公,专业移动办公平台 https://zx.naton.cn/
【总监】十二春秋之, 3483099@qq.com ;
【Master】zelo, 616701261@qq.com ;
【运营】运维艄公, 897221533@qq.com ;
【产品设计】流浪猫, 364994559@qq.com ;
【体验设计】兜兜, 2435632247@qq.com ;
【iOS】淘码小工, 492395860@qq.com ; iMcG33K, imcg33k@gmail.com ;
【android】人猿居士, 1059604515@qq.com ;思路的顿悟, 1217022114@qq.com ;
【java】首席工程师MR_W, feixue300@qq.com ;
【测试】土镜问道, 847071279@qq.com ;
【数据】fox009521, 42151960@qq.com ;
【安全】保密,你懂的。
EventBroker学习
前言
话说EventBroker这玩意已经不是什么新鲜货了,记得第一次接触这玩意是在进第二家公司的时候,公司产品基础架构层中集成了分布式消息中间件,在.net基础服务层中使用EventBroker的模式将消息组装成事件,支持同域、跨域和跨机器进行事件的发布和订阅,后来才知道这玩意叫做EventBroker。不得不承认,这是一个非常聪明的东西,它在内部高度封装了消息和事件的处理,将上层应用的事件和委托的依赖进行解耦,并且提供非常简洁的方式进行开发。OK,本篇文章只是实现了一个简化版本的EventBroker,功能非常有限,也没有集成消息组件,所以也不支持跨域和跨机器的分布式应用了,甚至没有经过严格测试(比如并发处理、跨线程处理等等),社区上更好的实现很多。所以必须声明:只是实验性代码,纯粹练手,带着学习的态度写代码,coding不易,大家不喜勿喷
准备
本篇主要使用.net C#技术,包括委托、反射、弱引用和弱事件模式,写代码也是为了学习这些,找找码感。说明:为了不影响阅读,所贴代码均有一些阉割,如需源码,后续我把附件传上来,不过这源码真没啥东西,我上传就是自己做一个记录,存储下来
思路
思路不用多说,网上搜一下会有很多信息,我比较懒,直接贴一张网上的图可以明确表现出系统的交互场景和交互流程
应用
在应用层使用EventBroker,需要在应用中针对对象进行Register,一般中大型项目使用IOC容器都提供在对象创建时注入特征,比如:
1
2
3
4
5
6
|
// 示范代码 private void OnObjectBuild(ObjectModel builder, object instance) { var broker = DIContainer.Resolve<IEventBroker>(); broker.Register(instance); } |
这样比较方便,避免在程序中手动Register,不过我这里只是简单实现,不涉及IOC和任何设计的东西,注册对象后,在我们的类中可以像如下的方式实现:
1
2
|
public event EventHandler<EventModelArgs< string >> MessageArrived; |
以上是事件定义,我们可以把事件委托引用的方法定义在另一个类,而且两者完全不用依赖彼此
1
2
3
4
5
|
public void MessageReceived( object sender, EventModelArgs< string > message) { PrintOut(message.Data); } |
源码
- 源码目录结构,看看是不是比别的版本精简了?
- EventBroker,我暂且把这个叫事件总线,内部封装EventTopic,事件的发布者和订阅者信息都间接存储在总线上,除此之外,总线向外部提供统一的API接口,方便调用,相关接口如下:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950namespace
TinyEventBroker
{
public
class
EventBroker
{
private
readonly
EventTopicCollection topics
=
new
EventTopicCollection();
/// <summary>
/// 事件主题集合列表
/// </summary>
public
EventTopicCollection Topics
{
get
{
return
topics; }
}
/// <summary>
/// 事件场景
/// </summary>
public
virtual
EventScope EventScope {
get
{
return
EventScope.Local; } }
/// <summary>
/// 将对象注入到事件总线上
/// </summary>
public
void
Register(
object
target)
{
BindingFlags bingdings = BindingFlags.Instance | BindingFlags.Static
| BindingFlags.Public | BindingFlags.NonPublic;
RegisterPublication(target, bingdings);
RegisterSubscription(target, bingdings);
}
/// <summary>
/// 注册发布者
/// </summary>
private
void
RegisterPublication(
object
target, BindingFlags bindings)
{
// ……
}
/// <summary>
/// 注册订阅者
/// </summary>
/// <param name="target"></param>
/// <param name="bindings"></param>
private
void
RegisterSubscription(
object
target, BindingFlags bindings)
{
// ……
}
}
}
- EventTopic,这个我把它称为事件主题,一个主题可以包含多个发布者和订阅者并提供一些处理,主题管理器内部将事件进行桥接,并动态调用订阅者方法,相关接口如下:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586public
class
EventTopic
{
public
EventTopic() { }
public
EventTopic(
string
name)
:
this
()
{
this
.Name = name;
}
/// <summary>
/// 事件主题标识
/// </summary>
public
string
Name {
get
;
set
; }
private
List<EventPublication> publishers =
new
List<EventPublication>();
/// <summary>
/// 发布者列表
/// </summary>
internal
List<EventPublication> Publishers
{
get
{
return
publishers; }
set
{ publishers = value; }
}
private
List<EventSubscription> subscribers =
new
List<EventSubscription>();
/// <summary>
/// 订阅者列表
/// </summary>
internal
List<EventSubscription> Subscribers
{
get
{
return
subscribers; }
set
{ subscribers = value; }
}
/// <summary>
/// 增加发布者
/// </summary>
internal
void
AddPublication(EventPublication publisher)
{
EventContext.Instance.WriteTo(
"主题:{0} 添加发布者{1}"
, Name, publisher);
publisher.EventFired += OnEventFired;
publishers.Add(publisher);
}
/// <summary>
/// 增加订阅者
/// </summary>
internal
void
AddSubscription(EventSubscription subscriber)
{
EventContext.Instance.WriteTo(
"主题:{0} 添加订阅者{1}"
, Name, subscriber);
subscribers.Add(subscriber);
}
/// <summary>
/// 移除发布者
/// </summary>
internal
void
RemovePublication(EventPublication publisher)
{
EventContext.Instance.WriteTo(
"主题:{0} 移除发布者{1}"
, Name, publisher);
publishers.Remove(publisher);
}
/// <summary>
/// 移除订阅者
/// </summary>
internal
void
RemoveSubscription(EventSubscription subscriber)
{
EventContext.Instance.WriteTo(
"主题:{0} 移除订阅者{1}"
, Name, subscriber);
subscribers.Remove(subscriber);
}
internal
void
OnEventFired(EventPublication publication,
object
sender, EventArgs args)
{
// ......
}
private
void
CheckInvalidPublications()
{
// ......
}
private
void
CheckInvalidSubscriptions()
{
// ......
}
}
- Publisher,订阅者,使用弱引用来存储目标对象,防止目标对象无法释放造成内存泄露
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Reflection;
using
System.Text;
using
System.Threading.Tasks;
namespace
TinyEventBroker
{
/// <summary>
/// 发布者
/// </summary>
internal
class
EventPublication
{
/// <summary>
/// 弱引用对象包装器
/// </summary>
private
readonly
WeakReference wrapper;
/// <summary>
/// 事件名称
/// </summary>
private
readonly
string
eventName;
/// <summary>
/// 事件处理委托类型
/// </summary>
private
readonly
Type eventHandleType;
/// <summary>
/// 对象名称,用于显示
/// </summary>
private
readonly
string
targetName;
/// <summary>
/// 事件定义,用来桥接对象的Event
/// </summary>
public
event
TopicEventHandler EventFired;
public
EventPublication(
object
target,
string
eventName)
{
wrapper =
new
WeakReference(target);
this
.eventName = eventName;
this
.targetName = target.GetType().Name;
EventInfo info = target.GetType().GetEvent(EventName);
eventHandleType = info.EventHandlerType;
Delegate handler = Delegate.CreateDelegate(
EventHandleType,
this
,
this
.GetType().GetMethod(
"OnEventFired"
));
info.AddEventHandler(target, handler);
}
/// <summary>
/// 获取对象引用
/// </summary>
public
object
Target
{
get
{
return
wrapper.Target; }
}
/// <summary>
/// 对象名称,用于显示
/// </summary>
public
string
TargetName
{
get
{
return
targetName; }
}
/// <summary>
/// 判断对象是否存活
/// </summary>
public
bool
IsAlive
{
get
{
return
wrapper.IsAlive; }
}
/// <summary>
/// 事件名称
/// </summary>
public
string
EventName
{
get
{
return
eventName; }
}
/// <summary>
/// 事件处理类型
/// </summary>
public
Type EventHandleType
{
get
{
return
eventHandleType; }
}
public
virtual
void
OnEventFired(
object
sender, EventArgs e)
{
var
handle = EventFired;
if
(handle !=
null
)
handle(
this
, sender, e);
}
public
override
string
ToString()
{
return
string
.Format(
"[{0} - {1}]"
, targetName, eventName);
}
}
}
- 订阅者,依然使用弱引用来保存目标对象
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Threading;
using
System.Threading.Tasks;
namespace
TinyEventBroker
{
/// <summary>
/// 订阅者
/// </summary>
public
class
EventSubscription
{
/// <summary>
/// 弱引用对象包装器
/// </summary>
private
readonly
WeakReference wrapper;
/// <summary>
/// 方法名
/// </summary>
private
readonly
string
methodName;
/// <summary>
/// 对象名称,仅作显示
/// </summary>
private
readonly
string
targetName;
public
EventSubscription(
object
target,
string
methodName)
{
this
.wrapper =
new
WeakReference(target);
this
.methodName = methodName;
targetName = target.GetType().Name;
}
/// <summary>
/// 对象是否存活
/// </summary>
public
bool
IsAlive
{
get
{
return
wrapper.IsAlive; }
}
/// <summary>
/// 订阅者对象方法名
/// </summary>
public
string
MethodName {
get
{
return
methodName; } }
/// <summary>
/// 订阅者对象,通过弱引用包装访问
/// </summary>
public
object
Target {
get
{
return
wrapper.Target; } }
/// <summary>
/// 订阅者对象显式名
/// </summary>
public
string
TargetName {
get
{
return
targetName; } }
internal
virtual
void
HandleEvent(EventPublication publication,
object
sender, EventArgs args)
{
Delegate handler = Delegate.CreateDelegate(
publication.EventHandleType, Target, methodName);
handler.DynamicInvoke(sender, args);
}
public
override
string
ToString()
{
return
string
.Format(
"[{0} - {1}]"
, targetName, methodName);
}
}
}
-
1
EventScope,这东西只是保留属性,以后扩展的时候用
初步测试结果
引用
针对弱引用这个东东,其实直接使用弱事件模式,微软已经封装好了的
Weak Event Patterns,Weak Event in C#
结语
本篇只是EventBroker的简单实现,纯粹就是学习练手,我想,如果后续我有充足的时间,或者工作环境允许,我可以实现得更好,比如可以在内部封装多钟策略,异常处理策略、异步事件策略、处理并发、线程安全的考虑等等。更而甚之,可以将它进行抽象和扩展,加入消息中间件,实现分布式发布者和订阅者,那样就比较有实用价值了。不过写代码水平和效率有限,时间和精力也有限,工作是工作学习是学习,区区一文,聊表我的热情和开发,让代码和生活可以持续下去吧!
以上是关于web服务(同域和跨域)的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security基于Oauth2的SSO单点登录怎样做?一个注解搞定