RabbitMQ使用分析和高可用集群搭建
一、RabbitMQ 基础理解 RabbitMQ,是一个使用 erlang 编写的 AMQP(高级消息队列协议)的服务实现,简单来说,就是一个功能强大的消息队列服务。 概念理解: Producer: 消息发送者 RabbitMQ: Vhost: 相当于分组,每个vhost下数据是隔离的 Exchange: 路由器,接收消息,本根据RoutingKey分发消息 headers:消息头类型 路由器,内部应用 direct:精准匹配类型 路由器 topic:主题匹配类型 路由器,支持正则 模糊匹配 fanout:广播类型 路由器,RoutingKey无效 RoutingKey: 路由规则 Queue: 队列,用于存储消息(消息的目的地) Consumer: 消息消费者 持久化: 一个好的消息队列当然需要消息持久化功能,服务宕机,未消费消息不丢失,RabbitMQ持久化分为Exchange、Queue、Message Exchange 和 Queue 持久化 指持久化Exchange、Queue 元数据,持久化的是自身,服务宕机,Exchange 和 Queue 自身就没有了 Message 持久化 顾名思义 把每一条消息体持久化,服务宕机,消息不丢失 Durable 持久、Transient 临时,Queue新建类似 分析理解: 便于更直观的理解,把 RabbitMQ 的消息流对比与Http Rest接口更家熟悉形象 www.xxx.com/webappPath/trade/getOrder -> getOrder(message) GET RabbitMQ Server:同比 域名 www.xxx.com,只有通过域名才能到达 Server Vhost:同比 /webappPath,一个域名可能指向多个app Exchange:同比 /trade,trade/* 下有多个method,但是需要先到达这个Class RoutingKey:同比 /getOrder,只有完成的 URL 才是有效的,才能确定到具体的方法 Queue:同比 getOrder(message) 消息的最终目的地 Exchange Type: 同比 GET,但是Rest MethodType是整个URL的Type,而不是 Queue 以上只是为了更好理解,千万不要混淆 Producer / Consumer 就很好理解了,基于AMQP协议链接RabbitMQ Server,发送消息 / 接收消息 二、RabbitMQ 消息确认策略分析 Confrim / Transaction 概念应用 RabbitMQ 提供了两种可靠性的确认策略 Confrim / Transaction,Producer […]
View DetailsCurrents 云计算报告:容器正流行,Serverless 未成熟
云计算公司 DigitalOcean 近日发布了2018年6月 Currents 云计算季度报告,该报告对全球 5000 名行业专业人士进行调查。报告显示,随着容器技术和相关管理工具在过去一年的快速发展,49% 的受访开发者表示目前正在使用容器。Serverless 则依然处于初期阶段,有一大半的受访者表示对 Serverless 不了解。 具体来看,随着容器技术的普及,近一半(49%)的受访者表示他们目前正在使用容器。其中, 40% 的人只使用容器进行测试和开发,另外 60% 也会将其用于生产。之所以选择容器,主要是因为其高扩展性,以及能够简化和加速测试。 在具体方案的选择上,容器集群管理系统 Kubernetes 总体上最受欢迎。不过在小公司中,更多地是使用 Docker Swarm(41% 使用 Swarm ,31% 使用 Kubernetes )。 与容器的流行不同,Serverless 似乎仍处于早期阶段,有一大半的受访者表示对 Serverless 不太了解。Serverless 从出现至今已有两三年的时间,但一直没有公认的权威定义。 在使用容器的开发者中,使用 JavaScript 的占大多数,其次是 Python 和 PHP 。 更多详情可查阅完整报告 from: https://www.oschina.net/news/97689/developers-in-cloud
View DetailsSignalR官方底层连接示例(中文)
由于公司项目用到了微软的SignalR,项目后期出现了写Cookie和跨域的问题。所以汉化了官方的示例,给小伙伴们普及一下入门知识。 进来后有另一个用户加入的效果: 发个广播: 设置名字,名字是记录到cookie里的,设置的时候别忘了加path,不然SignalR获取不到。 ……其实SignalR对Cookie和跨域已经提供了支付和示例。 直接上代码:SignalRDemo.zip
View DetailsConcurrentDictionary 类
表示可由多个线程同时访问的键/值对的线程安全集合。 命名空间: System.Collections.Concurrent 程序集: mscorlib(位于 mscorlib.dll) 继承层次结构 System.Object System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 语法 C#
1 2 3 4 5 6 7 8 |
[SerializableAttribute] [ComVisibleAttribute(false)] [HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] public class ConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>> |
类型参数 TKey 字典中的键的类型。 TValue 字典中的值的类型。 构造函数 名称 说明 ConcurrentDictionary<TKey, TValue>() 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例为空,具有默认的并发级别和默认的初始容量,并为键类型使用默认比较器。 ConcurrentDictionary<TKey, TValue>(IEnumerable<KeyValuePair<TKey, TValue>>) 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例包含从指定的 IEnumerable<T> 中复制的元素,具有默认的并发级别和默认的初始容量,并为键类型使用默认比较器。 ConcurrentDictionary<TKey, TValue>(IEnumerable<KeyValuePair<TKey, TValue>>, IEqualityComparer<TKey>) 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例包含从指定的 IEnumerable 中复制的元素,具有默认的并发级别和默认的初始容量,并使用指定的 IEqualityComparer<T>。 ConcurrentDictionary<TKey, TValue>(IEqualityComparer<TKey>) 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例为空,具有默认的并发级别和容量,并使用指定的System.Collections.Generic.IEqualityComparer<T>。 ConcurrentDictionary<TKey, TValue>(Int32, IEnumerable<KeyValuePair<TKey, TValue>>, IEqualityComparer<TKey>) 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例包含从指定的 IEnumerable 中复制的元素并使用指定的System.Collections.Generic.IEqualityComparer<T>。 ConcurrentDictionary<TKey, TValue>(Int32, Int32) 初始化 ConcurrentDictionary<TKey, TValue> 类的新实例,该实例为空,具有指定的并发级别和容量,并为键类型使用默认比较器。 ConcurrentDictionary<TKey, TValue>(Int32, Int32, IEqualityComparer<TKey>) 初始化 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 类的新实例,该实例为空,具有指定的并发级别和指定的初始容量,并使用指定的 System.Collections.Generic.IEqualityComparer<T>。 属性 名称 说明 Count 获取包含在 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 中的键/值对的数目。 IsEmpty 获取一个值,该值指示 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 是否为空。 Item[TKey] 获取或设置与指定的键关联的值。 Keys 获得一个包含 System.Collections.Generic.Dictionary<TKey, TValue> 中的键的集合。 Values 获取包含 System.Collections.Generic.Dictionary<TKey, TValue> 中的值的集合。 方法 名称 说明 AddOrUpdate(TKey, TValue, Func<TKey, TValue, TValue>) 如果该键不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中;如果该键已经存在,则通过使用指定的函数更新 ConcurrentDictionary<TKey, TValue> 中的键/值对。 AddOrUpdate(TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>) 如果该键不存在,则使用指定函数将键/值对添加到 ConcurrentDictionary<TKey, TValue>;如果该键已存在,则使用该函数更新 ConcurrentDictionary<TKey, TValue>中的键/值对。 Clear() 将所有键和值从 ConcurrentDictionary<TKey, TValue> 中移除。 ContainsKey(TKey) 确定是否 ConcurrentDictionary<TKey, TValue> 包含指定键。 Equals(Object) 确定指定的对象是否等于当前对象。(继承自 Object。) Finalize() 在垃圾回收将某一对象回收前允许该对象尝试释放资源并执行其他清理操作。(继承自 Object。) GetEnumerator() 返回循环访问 ConcurrentDictionary<TKey, TValue> 的枚举数。 GetHashCode() 作为默认哈希函数。(继承自 Object。) GetOrAdd(TKey, TValue) 如果该键不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中。 GetOrAdd(TKey, Func<TKey, TValue>) 如果该键不存在,则通过使用指定的函数将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中。 GetType() 获取当前实例的 Type。(继承自 Object。) MemberwiseClone() 创建当前 Object 的浅表副本。(继承自 Object。) ToArray() 将 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 中存储的键和值对复制到新数组中。 ToString() 返回表示当前对象的字符串。(继承自 Object。) TryAdd(TKey, TValue) 尝试将指定的键和值添加到 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 中。 TryGetValue(TKey, TValue) 尝试从 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 获取与指定的键关联的值。 TryRemove(TKey, TValue) 尝试从 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 中移除并返回具有指定键的值。 TryUpdate(TKey, TValue, TValue) 将指定键的现有值与指定值进行比较,如果相等,则用第三个值更新该键。 示例 C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
class CD_Ctor { // Demonstrates: // ConcurrentDictionary<TKey, TValue> ctor(concurrencyLevel, initialCapacity) // ConcurrentDictionary<TKey, TValue>[TKey] static void Main() { // We know how many items we want to insert into the ConcurrentDictionary. // So set the initial capacity to some prime number above that, to ensure that // the ConcurrentDictionary does not need to be resized while initializing it. int NUMITEMS = 64; int initialCapacity = 101; // The higher the concurrencyLevel, the higher the theoretical number of operations // that could be performed concurrently on the ConcurrentDictionary. However, global // operations like resizing the dictionary take longer as the concurrencyLevel rises. // For the purposes of this example, we'll compromise at numCores * 2. int numProcs = Environment.ProcessorCount; int concurrencyLevel = numProcs * 2; // Construct the dictionary with the desired concurrencyLevel and initialCapacity ConcurrentDictionary<int, int> cd = new ConcurrentDictionary<int, int>(concurrencyLevel, initialCapacity); // Initialize the dictionary for (int i = 0; i < NUMITEMS; i++) cd[i] = i * i; Console.WriteLine("The square of 23 is {0} (should be {1})", cd[23], 23 * 23); } } |
[…]
View DetailsSignalR 跨域解决方案全面
SignalR 分:PersistentConnection和Hub 2种模式。 跨域又分:UseCors和JsonP 2种方法 所以例子写了4种。 核心代码: UseCors
1 2 3 4 5 6 7 8 9 10 11 12 |
//PersistentConnection Mode app.UseCors(CorsOptions.AllowAll); //PersistentConnection Mode app.MapSignalR<MyConnection>("/server", new ConnectionConfiguration() { }); // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888 //Hub Mode app.MapSignalR("/lcc", new HubConfiguration()); |
Use JsonP
1 2 3 4 5 6 7 8 9 |
//PersistentConnection Mode app.MapSignalR<MyConnection>("/server", new ConnectionConfiguration() { EnableJSONP = true }); // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888 //Hub Mode app.MapSignalR("/lcc", new HubConfiguration() { EnableJSONP = true }); |
Cross HUb 前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// 建立对应server端Hub class的对象,请注意geffChat的第一个字母要改成小写 var chat = $.connection.myHub; $.connection.hub.url = 'http://localhost:2001/lcc'; //把connection打开 $.connection.hub.start().done(function () { chat.server.hello(); }); // 定义client端的javascript function,供server端hub,通过dynamic的方式,调用所有Clients的javascript function chat.client.sendMessage = function (message) { //当server端调用sendMessage时,将server push的message数据,呈现在wholeMessage中 $('#messages').append('<li>' + message + '</li>'); }; $("#broadcast").click(function () { chat.server.sendMessage($('#msg').val()); $('#msg').val(""); }); $("#btnStop").click(function () { $.connection.hub.stop(); }); |
Cross Connection 前端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var connection = $.connection("http://localhost:2001/server"); connection.received(function (data) { $('#messages').append('<li>' + data + '</li>'); }); connection.start(); $("#broadcast").click(function () { connection.send($('#msg').val()); }); $("#btnStop").click(function () { connection.stop(); }); |
JsonP HUb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// 建立对应server端Hub class的对象,请注意geffChat的第一个字母要改成小写 var chat = $.connection.myHub; $.connection.hub.url = 'http://localhost:16727/lcc'; //把connection打开 $.connection.hub.start({ jsonp: true }).done(function () { chat.server.hello(); }); // 定义client端的javascript function,供server端hub,通过dynamic的方式,调用所有Clients的javascript function chat.client.sendMessage = function (message) { //当server端调用sendMessage时,将server push的message数据,呈现在wholeMessage中 $('#messages').append('<li>' + message + '</li>'); }; $("#broadcast").click(function () { chat.server.sendMessage($('#msg').val()); $('#msg').val(""); }); $("#btnStop").click(function () { $.connection.hub.stop(); }); |
JsonP connection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var connection = $.connection("http://localhost:16727/server"); connection.received(function (data) { $('#messages').append('<li>' + data + '</li>'); }); connection.start({ jsonp: true }); $("#broadcast").click(function () { connection.send($('#msg').val()); }); $("#btnStop").click(function () { connection.stop(); }); |
代码下载:http://download.csdn.net/detail/shikyoh/9734460 from: https://www.cnblogs.com/shikyoh/p/6272679.html
View DetailsActivemq 平台搭建与C#示列
ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。 特性 多种语言和协议编写客户端。语言: Java、C、C++、C#、Ruby、Perl、Python、PHP。应用协议:OpenWire、Stomp REST、WS Notification、XMPP、AMQP 完全支持JMS1.1和J2EE 1.4规范 (持久化,XA消息,事务) 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去,而且也支持Spring2.0的特性 通过了常见J2EE服务器(如 Geronimo、JBoss 4、GlassFish、WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上 支持多种传送协议:in-VM、TCP、SSL、NIO、UDP、JGroups、JXTA 支持通过JDBC和journal提供高速的消息持久化 从设计上保证了高性能的集群,客户端-服务器,点对点 支持Ajax 支持与Axis的整合 可以很容易得调用内嵌JMS provider,进行测试 环境准备 我以windows7为列子 windows 7 jdk1.6+ 并在windows下配置好环境变量等,具体可以看 http://jingyan.baidu.com/article/ff41162596a77912e4823716.html 下载最新版activemq http://activemq.apache.org/activemq-5121-release.html 安装 解压下载好的安装包,至本地任何磁盘 启动activemq服务 启动成功后的界面是 如果出现major.minor version51.0 之类的错误,都是java版本安装错误的问题,安装1.6+以上的版本就能解决 启动成功后,http://localhost:8161/admin,默认用户名和密码admin/admin。如果你想修改用户名和密码的话,在conf/jetty-realm.properties中修改即可。 如果需要修改端口可以在jetty文件中修改 管理员界面如下 ActiviteMQ接收和发送消息基本流程 摘自 http://www.cnblogs.com/hoojo/p/active_mq_jms_apache_activeMQ.html 发送消息的基本步骤: (1)、创建连接使用的工厂类JMS ConnectionFactory (2)、使用管理对象JMS ConnectionFactory建立连接Connection,并启动 (3)、使用连接Connection 建立会话Session (4)、使用会话Session和管理对象Destination创建消息生产者MessageSender (5)、使用消息生产者MessageSender发送消息 消息接收者从JMS接受消息的步骤 (1)、创建连接使用的工厂类JMS ConnectionFactory (2)、使用管理对象JMS ConnectionFactory建立连接Connection,并启动 (3)、使用连接Connection 建立会话Session (4)、使用会话Session和管理对象Destination创建消息接收者MessageReceiver (5)、使用消息接收者MessageReceiver接受消息,需要用setMessageListener将MessageListener接口绑定到MessageReceiver消息接收者必须实现了MessageListener接口,需要定义onMessage事件方法。 C#消息队列写入 ActiveMQ官方网站下载最新版的Apache.NMS,网址:http://activemq.apache.org/nms/download.html,需要下载Apache.NMS和Apache.NMS.ActiveMQ两个bin包 http://www.apache.org/dyn/closer.lua/activemq/apache-nms/1.7.0/Apache.NMS.ActiveMQ-1.7.1-bin.zip 创建C#项目,将这两个DLL添加到项目中。 写入地址如下 写入账号,密码如下 写入代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
namespace ConsoleApplication21 { class Program { static void Main(string[] args) { String QueuesNameESF = "queue://test.log"; Uri _uri = new Uri(String.Concat("activemq:tcp://10.58.8.239:61616")); IConnectionFactory factory = new ConnectionFactory(_uri); using (IConnection conn = factory.CreateConnection("admin", "manager")) { using (ISession session = conn.CreateSession()) { IDestination destination = SessionUtil.GetDestination(session, QueuesNameESF); using (IMessageProducer producer = session.CreateProducer(destination)) { conn.Start(); //可以写入字符串,也可以是一个xml字符串等 ITextMessage request = session.CreateTextMessage("messsage"); producer.Send(request); } } } } } |
写入后,可以查看 读取代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System; using Apache.NMS; using Apache.NMS.ActiveMQ; using Apache.NMS.Util; namespace ConsoleApplication21 { class Program { static void Main(string[] args) { String QueuesNameESF = "queue://test.log"; Uri _uri = new Uri(String.Concat("activemq:tcp://10.58.8.239:61616?wireFormat.maxInactivityDuration=0")); IConnectionFactory factory = new ConnectionFactory(_uri); using (IConnection conn = factory.CreateConnection("admin", "manager")) { using (ISession session = conn.CreateSession()) { conn.Start(); IDestination destination = SessionUtil.GetDestination(session, QueuesNameESF); using (IMessageConsumer consumer = session.CreateConsumer(destination)) { ITextMessage message = consumer.Receive() as ITextMessage; Console.Write(message.Text); } } } Console.ReadLine(); } } } |
from:https://www.cnblogs.com/woxpp/p/5001373.html
View DetailsCentOS7安装ActiveMQ
1、下载activemq,下载地址:http://archive.apache.org/dist/activemq。测试版本为apache-activemq-5.14.1。 2、在/ursr/local/目录下新建activemq文件夹,并进入该文件夹,执行如下命令解压文件。
1 2 3 |
cd /usr/local mkdir activemq tar -xzvf apache-activemq-5.14.1-bin.tar.gz |
3、在/etc/init.d/目录增加增加activemq文件,文件内容为:
1 2 |
cd /etc/init.d/ vi activemq |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #!/bin/sh # # /etc/init.d/activemq # chkconfig: 345 63 37 # description: activemq servlet container. # processname: activemq 5.14.1 # Source function library. #. /etc/init.d/functions # source networking configuration. #. /etc/sysconfig/network #export JAVA_HOME=/ export CATALINA_HOME=/usr/local/activemq/apache-activemq-5.14.1 case $1 in start) sh $CATALINA_HOME/bin/activemq start ;; stop) sh $CATALINA_HOME/bin/activemq stop ;; restart) sh $CATALINA_HOME/bin/activemq stop sleep 1 sh […]
View DetailsWebApi 跨域问题解决方案:CORS
正文 前言:上篇总结了下WebApi的接口测试工具的使用,这篇接着来看看WebAPI的另一个常见问题:跨域问题。本篇主要从实例的角度分享下CORS解决跨域问题一些细节。 WebApi系列文章 C#进阶系列——WebApi接口测试工具:WebApiTestClient C#进阶系列——WebApi 跨域问题解决方案:CORS C#进阶系列——WebApi身份认证解决方案:Basic基础认证 C#进阶系列——WebApi接口传参不再困惑:传参详解 C#进阶系列——WebApi接口返回值不困惑:返回值类型详解 C#进阶系列——WebApi异常处理解决方案 C#进阶系列——WebApi区域Area使用小结 一、跨域问题的由来 同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容。 正是由于这个原因,我们不同项目之间的调用就会被浏览器阻止。比如我们最常见的场景:WebApi作为数据服务层,它是一个单独的项目,我们的MVC项目作为Web的显示层,这个时候我们的MVC里面就需要调用WebApi里面的接口取数据展现在页面上。因为我们的WebApi和MVC是两个不同的项目,所以运行起来之后就存在上面说的跨域的问题。 二、跨域问题解决原理 CORS全称Cross-Origin Resource Sharing,中文全称跨域资源共享。它解决跨域问题的原理是通过向http的请求报文和响应报文里面加入相应的标识告诉浏览器它能访问哪些域名的请求。比如我们向响应报文里面增加这个Access-Control-Allow-Origin:http://localhost:8081,就表示支持http://localhost:8081里面的所有请求访问系统资源。其他更多的应用我们就不一一列举,可以去网上找找。 三、跨域问题解决细节 下面我就结合一个简单的实例来说明下如何使用CORS解决WebApi的跨域问题。 1、场景描述 我们新建两个项目,一个WebApi项目(下图中WebApiCORS),一个MVC项目(下图中Web)。WebApi项目负责提供接口服务,MVC项目负责页面呈现。如下: 其中,Web与WebApiCORS端口号分别为“27239”和“27221”。Web项目需要从WebApiCORSS项目里面取数据,很显然,两个项目端口不同,所以并不同源,如果使用常规的调用方法肯定存在一个跨域的问题。 简单介绍下测试代码,Web里面有一个HomeController
1 2 3 4 5 6 7 8 |
public class HomeController : Controller { // GET: Home public ActionResult Index() { return View(); } } |
对应的Index.cshtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<html> <head> <meta name="viewport" content="width=device-width" /> <title>Index</title> <script src="~/Content/jquery-1.9.1.js"></script> <link href="~/Content/bootstrap/css/bootstrap.css" rel="stylesheet" /> <script src="~/Content/bootstrap/js/bootstrap.js"></script> <script src="~/Scripts/Home/Index.js"></script> </head> <body> 测试结果:<div id="div_test"> </div> </body> </html> |
Index.js文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var ApiUrl = "http://localhost:27221/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Charging/GetAllChargingData", data: {}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); |
WebApiCORS项目里面有一个测试的WebApi服务ChargingController
1 2 3 4 5 6 7 8 9 10 11 12 |
public class ChargingController : ApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet] public string GetAllChargingData() { return "Success"; } } |
配置WebApi的路由规则为通过action调用。WebApiConfig.cs文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } |
2、场景测试 1)我们不做任何的处理,直接将两个项目运行起来。看效果如何 IE浏览器: 谷歌浏览器: 这个结果另博主也很吃惊,不做任何跨域处理,IE10、IE11竟然可以直接请求数据成功,而同样的代码IE8、IE9、谷歌浏览器却不能跨域访问。此原因有待查找,应该是微软动了什么手脚。 2)使用CORS跨域 首先介绍下CORS如何使用,在WebApiCORS项目上面使用Nuget搜索“microsoft.aspnet.webapi.cors”,安装第一个 然后在App_Start文件夹下面的WebApiConfig.cs文件夹配置跨域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //跨域配置 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } |
我们暂定三个“*”号,当然,在项目中使用的时候一般需要指定对哪个域名可以跨域、跨域的操作有哪些等等。这个在下面介绍。 IE10、IE11 谷歌浏览器 IE8、IE9 这个时候又有新问题了,怎么回事呢?我都已经设置跨域了呀,怎么IE8、9还是不行呢?这个时候就有必要说说CORS的浏览器支持问题了。网上到处都能搜到这张图: 上图描述了CORS的浏览器支持情况,可以看到IE8、9是部分支持的。网上说的解决方案都是Internet Explorer 8 、9使用 XDomainRequest 对象实现CORS。是不是有这么复杂?于是博主各种百度寻找解决方案。最后发现在调用处指定 jQuery.support.cors = true; 这一句就能解决IE8、9的问题了。具体是在Index.js里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
jQuery.support.cors = true; var ApiUrl = "http://localhost:27221/"; $(function () { $.ajax({ type: "get", url: ApiUrl + "api/Charging/GetAllChargingData", data: {}, success: function (data, status) { if (status == "success") { $("#div_test").html(data); } }, error: function (e) { $("#div_test").html("Error"); }, complete: function () { } }); }); |
这句话的意思就是指定浏览器支持跨域。原来IE9以上版本的浏览器、谷歌、火狐等都默认支持跨域,而IE8、9却默认不支持跨域,需要我们指定一下。你可以在你的浏览器里面打印jQuery.support.cors看看。这样设置之后是否能解决问题呢?我们来看效果: 问题完美解决。至于网上说的CORS对IE8、9的解决方案XDomainRequest是怎么回事,有待实例验证。 3)CORS的具体参数设置。 上文我们使用
1 |
config.EnableCors(new EnableCorsAttribute("*", "*", "*")); |
这一句解决了跨域问题,上面说了,这种*号是不安全的。因为它表示只要别人知道了你的请求url,任何请求都可以访问到你的资源。这是相当危险的。所以需要我们做一些配置,限制访问权限。比如我们比较常见的做法如下: 配置方法一、在Web.Config里面(PS:这两张图源自:http://www.cnblogs.com/moretry/p/4154479.html) 然后在WebApiConfig.cs文件的Register方法里面 配置方法二、如果你只想对某一些api做跨域,可以直接在API的类上面使用特性标注即可。 光子:先在WebApiConfig.cs文件的Register方法中添加
1 |
config.EnableCors(); |
然后在控制器或方法上添加注解
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[EnableCors(origins: "http://localhost:8081/", headers: "*", methods: "GET,POST,PUT,DELETE")] public class ChargingController : ApiController { /// <summary> /// 得到所有数据 /// </summary> /// <returns>返回数据</returns> [HttpGet] public string GetAllChargingData() { return "Success"; } } |
四、总结 以上就是一个简单的CORS解决WebApi跨域问题的实例,由于博主使用WebApi的时间并不长,所以很多理论观点未必成熟,如果有说的不对的,欢迎指出。博主在此多谢啦。 from:http://www.cnblogs.com/landeanfen/p/5177176.html
View DetailsWeb API POST传参不要加参数名
后端
1 2 3 4 5 6 7 8 9 10 11 |
// POST api/<controller> public string Post([FromBody]List<User> value) { StringBuilder sb = new StringBuilder(); foreach (User user in value) { sb.AppendLine(user.Username); } return sb.ToString(); } |
前端
1 2 3 4 5 6 7 8 |
$.ajax({ method: "Post", url: "http://localhost:37085/api/ValList", data: { <strong>"":</strong> [{ "Id": 1, "Username": "w3cnet" }] }, success: function(result) { console.log(result); } }); |
View Details
CentOS系统中常用查看日志命令
cat tail -f 日 志 文 件 说 明 /var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一 /var/log/secure 与安全相关的日志信息 /var/log/maillog 与邮件相关的日志信息 /var/log/cron 与定时任务相关的日志信息 /var/log/spooler 与UUCP和news设备相关的日志信息 /var/log/boot.log 守护进程启动和停止相关的日志消息 系统: # uname -a # 查看内核/操作系统/CPU信息 # cat /etc/issue # cat /etc/redhat-release # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # hostname # 查看计算机名 # lspci -tv # 列出所有PCI设备 # lsusb -tv # 列出所有USB设备 # lsmod # 列出加载的内核模块 # env # 查看环境变量 资源: # free -m # 查看内存使用量和交换区使用量 # df -h # 查看各分区使用情况 # du -sh <目录名> […]
View Details