| 返回状态 | ASP.NET MVC | ASP.NET Core | ASP.NET Web API |
| 200 视图 | return View(); | return View(); | - |
| 200 带模型的视图 | return View(Model); | return View(Model); | - |
| 200 空内容 | return new EmptyResult(); | return Ok(); | return Ok(); |
| 200 文本 | return Content(string); | return Ok(string); return Content(string); | return Ok(string); return Content(string); |
| 200 JSON | return Json(object); | return Json(T); // 强制 JSON return Ok(T); // 请求时可指定 Content-Type | return Json(T); // 强制 JSON return Ok(T); // 请求时可指定 Content-Type |
| 200 JaveScript | return JavaScript(string script); | ||
| 200 文件 | return File(); | return File(); return PhysicalFile(); | return File(); return PhysicalFile(); |
| 201 已创建 | return Created(location, content); 用于 Post 接口 | ||
| 301 永久跳转 | return RedirectPermanent(url); return RedirectToActionPermanent(url); return RedirectToRoutePermanent(object); | return RedirectPermanent(url); return RedirectToActionPermanent(url); return RedirectToRoutePermanent(object); | |
| 302 临时跳转 | return Redirect(url); return RedirectToAction(url); return RedirectToRoute(object); | return Redirect(url); return RedirectToAction(url); return RedirectToRoute(object); | return Redirect(url); return RedirectToRoute(object); |
| 400 错误的请求 | return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest); | return BadRequest(msg); | return BadRequest(msg); |
| 401 未授权 | return new HttpUnauthorizedResult("描述"); | return Unauthorized(msg); | return Unauthorized(msg); |
| 404 找不到文件或目录 | return HttpNotFound(); | return NotFound(msg); | return NotFound(msg); |
| 直接指定状态码 | return new HttpStatusCodeResult(HttpStatusCode.*); public enum HttpStatusCode { // // 摘要: // 等效于 HTTP 状态 100。 System.Net.HttpStatusCode.Continue 指示客户端可能继续其请求。 Continue = 100, // // 摘要: // 等效于 HTTP 状态 101。 System.Net.HttpStatusCode.SwitchingProtocols 指示正在更改协议版本或协议。 SwitchingProtocols = 101, // // 摘要: // 等效于 HTTP 状态 200。 System.Net.HttpStatusCode.OK 指示请求成功,且请求的信息包含在响应中。 这是最常接收的状态代码。 OK = 200, // // 摘要: // 等效于 HTTP 状态 201。 System.Net.HttpStatusCode.Created 指示请求导致在响应被发送前创建新资源。 Created = 201, // // 摘要: // 等效于 HTTP 状态 202。 System.Net.HttpStatusCode.Accepted 指示已接受请求做进一步处理。 Accepted = 202, // // 摘要: // 等效于 HTTP 状态 203。 System.Net.HttpStatusCode.NonAuthoritativeInformation 指示返回的元信息来自缓存副本而不是原始服务器,因此可能不正确。 NonAuthoritativeInformation = 203, // // 摘要: // 等效于 HTTP 状态 204。 System.Net.HttpStatusCode.NoContent 指示已成功处理请求并且响应已被设定为无内容。 NoContent = 204, // // 摘要: // 等效于 HTTP 状态 205。 System.Net.HttpStatusCode.ResetContent 指示客户端应重置(而非重新加载)当前资源。 ResetContent = 205, // // 摘要: // 等效于 HTTP 状态 206。 System.Net.HttpStatusCode.PartialContent 指示响应是包括字节范围的 GET 请求所请求的部分响应。 PartialContent = 206, // // 摘要: // 等效于 HTTP 状态 300。 System.Net.HttpStatusCode.MultipleChoices 指示请求的信息有多种表示形式。 默认操作是将此状态视为重定向,并遵循与此响应关联的 // Location 标头的内容。 MultipleChoices = 300, // // 摘要: // 等效于 HTTP 状态 300。 System.Net.HttpStatusCode.Ambiguous 指示请求的信息有多种表示形式。 默认操作是将此状态视为重定向,并遵循与此响应关联的 // Location 标头的内容。 Ambiguous = 300, // // 摘要: // 等效于 HTTP 状态 301。 System.Net.HttpStatusCode.MovedPermanently 指示请求的信息已移到 Location // 头中指定的 URI 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 MovedPermanently = 301, // // 摘要: // 等效于 HTTP 状态 301。 System.Net.HttpStatusCode.Moved 指示请求的信息已移到 Location 头中指定的 URI // 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 Moved = 301, // // 摘要: // 等效于 HTTP 状态 302。 System.Net.HttpStatusCode.Found 指示请求的信息位于 Location 标头中指定的 URI // 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 Found = 302, // // 摘要: // 等效于 HTTP 状态 302。 System.Net.HttpStatusCode.Redirect 指示请求的信息位于 Location 标头中指定的 // URI 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 原始请求方法为 POST 时,重定向的请求将使用 GET 方法。 Redirect = 302, // // 摘要: // 等效于 HTTP 状态 303。 作为 POST 的结果,System.Net.HttpStatusCode.SeeOther 将客户端自动重定向到 Location // 标头中指定的 URI。 用 GET 生成对 Location 标头所指定的资源的请求。 SeeOther = 303, // // 摘要: // 等效于 HTTP 状态 303。 作为 POST 的结果,System.Net.HttpStatusCode.RedirectMethod 将客户端自动重定向到 // Location 标头中指定的 URI。 用 GET 生成对 Location 标头所指定的资源的请求。 RedirectMethod = 303, // // 摘要: // 等效于 HTTP 状态 304。 System.Net.HttpStatusCode.NotModified 指示客户端的缓存副本是最新的。 未传输此资源的内容。 NotModified = 304, // // 摘要: // 等效于 HTTP 状态 305。 System.Net.HttpStatusCode.UseProxy 指示请求应使用位于 Location 标头中指定的 // URI 的代理服务器。 UseProxy = 305, // // 摘要: // 等效于 HTTP 状态 306。 System.Net.HttpStatusCode.Unused 是未完全指定的 HTTP/1.1 规范的建议扩展。 Unused = 306, // // 摘要: // 等效于 HTTP 状态 307。 System.Net.HttpStatusCode.TemporaryRedirect 指示请求信息位于 Location // 标头中指定的 URI 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 原始请求方法为 POST 时,重定向的请求还将使用 POST // 方法。 TemporaryRedirect = 307, // // 摘要: // 等效于 HTTP 状态 307。 System.Net.HttpStatusCode.RedirectKeepVerb 指示请求信息位于 Location // 标头中指定的 URI 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 标头。 原始请求方法为 POST 时,重定向的请求还将使用 POST // 方法。 RedirectKeepVerb = 307, // // 摘要: // 等效于 HTTP 状态 400。 System.Net.HttpStatusCode.BadRequest 指示服务器未能识别请求。 如果没有其他适用的错误,或者不知道准确的错误或错误没有自己的错误代码,则发送 // System.Net.HttpStatusCode.BadRequest。 BadRequest = 400, // // 摘要: // 等效于 HTTP 状态 401。 System.Net.HttpStatusCode.Unauthorized 指示请求的资源要求身份验证。 WWW-Authenticate // 标头包含如何执行身份验证的详细信息。 Unauthorized = 401, // // 摘要: // 等效于 HTTP 状态 402。 保留 System.Net.HttpStatusCode.PaymentRequired 以供将来使用。 PaymentRequired = 402, // // 摘要: // 等效于 HTTP 状态 403。 System.Net.HttpStatusCode.Forbidden 指示服务器拒绝满足请求。 Forbidden = 403, // // 摘要: // 等效于 HTTP 状态 404。 System.Net.HttpStatusCode.NotFound 指示请求的资源不在服务器上。 NotFound = 404, // // 摘要: // 等效于 HTTP 状态 405。 System.Net.HttpStatusCode.MethodNotAllowed 指示请求的资源上不允许请求方法(POST // 或 GET)。 MethodNotAllowed = 405, // // 摘要: // 等效于 HTTP 状态 406。 System.Net.HttpStatusCode.NotAcceptable 指示客户端已用 Accept 标头指示将不接受资源的任何可用表示形式。 NotAcceptable = 406, // // 摘要: // 等效于 HTTP 状态 407。 System.Net.HttpStatusCode.ProxyAuthenticationRequired 指示请求的代理要求身份验证。 // Proxy-authenticate 标头包含如何执行身份验证的详细信息。 ProxyAuthenticationRequired = 407, // // 摘要: // 等效于 HTTP 状态 408。 System.Net.HttpStatusCode.RequestTimeout 指示客户端没有在服务器期望请求的时间内发送请求。 RequestTimeout = 408, // // 摘要: // 等效于 HTTP 状态 409。 System.Net.HttpStatusCode.Conflict 指示由于服务器上的冲突而未能执行请求。 Conflict = 409, // // 摘要: // 等效于 HTTP 状态 410。 System.Net.HttpStatusCode.Gone 指示请求的资源不再可用。 Gone = 410, // // 摘要: // 等效于 HTTP 状态 411。 System.Net.HttpStatusCode.LengthRequired 指示缺少必需的 Content-length // 标头。 LengthRequired = 411, // // 摘要: // 等效于 HTTP 状态 412。 System.Net.HttpStatusCode.PreconditionFailed 指示为此请求设置的条件失败,且无法执行此请求。条件是用条件请求标头(如 // If-Match、If-None-Match 或 If-Unmodified-Since)设置的。 PreconditionFailed = 412, // // 摘要: // 等效于 HTTP 状态 413。 System.Net.HttpStatusCode.RequestEntityTooLarge 指示请求太大,服务器无法处理。 RequestEntityTooLarge = 413, // // 摘要: // 等效于 HTTP 状态 414。 System.Net.HttpStatusCode.RequestUriTooLong 指示 URI 太长。 RequestUriTooLong = 414, // // 摘要: // 等效于 HTTP 状态 415。 System.Net.HttpStatusCode.UnsupportedMediaType 指示请求是不受支持的类型。 UnsupportedMediaType = 415, // // 摘要: // 等效于 HTTP 状态 416。 System.Net.HttpStatusCode.RequestedRangeNotSatisfiable 指示无法返回从资源请求的数据范围,因为范围的开头在资源的开头之前,或因为范围的结尾在资源的结尾之后。 RequestedRangeNotSatisfiable = 416, // // 摘要: // 等效于 HTTP 状态 417。 System.Net.HttpStatusCode.ExpectationFailed 指示服务器未能符合 Expect // 标头中给定的预期值。 ExpectationFailed = 417, // // 摘要: // 等效于 HTTP 状态 426。 System.Net.HttpStatusCode.UpgradeRequired 指示客户端应切换为诸如 TLS/1.0 // 之类的其他协议。 UpgradeRequired = 426, // // 摘要: // 等效于 HTTP 状态 500。 System.Net.HttpStatusCode.InternalServerError 指示服务器上发生了一般错误。 InternalServerError = 500, // // 摘要: // 等效于 HTTP 状态 501。 System.Net.HttpStatusCode.NotImplemented 指示服务器不支持请求的函数。 NotImplemented = 501, // // 摘要: // 等效于 HTTP 状态 502。 System.Net.HttpStatusCode.BadGateway 指示中间代理服务器从另一代理或原始服务器接收到错误响应。 BadGateway = 502, // // 摘要: // 等效于 HTTP 状态 503。 System.Net.HttpStatusCode.ServiceUnavailable 指示服务器暂时不可用,通常是由于过多加载或维护。 ServiceUnavailable = 503, // // 摘要: // 等效于 HTTP 状态 504。 System.Net.HttpStatusCode.GatewayTimeout 指示中间代理服务器在等待来自另一个代理或原始服务器的响应时已超时。 GatewayTimeout = 504, // // 摘要: // 等效于 HTTP 状态 505。 System.Net.HttpStatusCode.HttpVersionNotSupported 指示服务器不支持请求的 // HTTP 版本。 HttpVersionNotSupported = 505 } |
附 ASP.NET Form 相关:
400:
Response.StatusCode = 400;
Response.Write("错误提示");
Response.End();情况:
马甲 App 添加链接 a(域名 A),该页面跳转至页面 b(域名 B),信任域名添加 B。
现象:
无法获取 token,即授权不成功。
原因:
马甲 App 是判断首次打开的域名(即本例中的域名 A)是否在信任域名中。
解决:
将上述两个域名都填到信任域名中,或直接添加链接 b,不使用链接 a 作跳转。
另外提醒:
信任域名是真实的 token,合作域名是临时的 token,区别是权限高低;
配置完域名白名单后,应该重启 App 再测试,因为客户端有缓存。
ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:
内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache
SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache
MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache
Nuget 安装:Pomelo.Extensions.Caching.MySql
Nuget 安装:Pomelo.Extensions.Caching.MySqlConfig.Tools(用于在 MySql 数据库中创建表和索引以进行分布式缓存的命令行工具(dotnet-mysql-cache))
2019.11 MySqlConfig.Tools 最新版本(2.0.2)不支持 .NetCore 3.0,暂时可手动创建表和索引。
2021.11 MySqlConfig.Tools 最新版(2.1.0)不支持 .Net 6.0。
未完待续,后续步骤类似于:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
services.AddDistributedMySqlCache()
按这两篇文章部署即可:
ASP.NET Core 缓存(Cache)之 Redis 缓存
ASP.NET Core 会话状态(Session State)
存储内容示例:

图中,
第 1 项为浏览器 A 中,在 Session 中设置键 count 值为 1 的结果;
第 2 项为浏览器 B 中,在 Session 中设置键 count 值为 3 的结果;
而第 3 项为设置 Cache 键 count 值为 8 的结果。
按这两篇文章部署即可:
ASP.NET Core 缓存(Cache)之 SQL Server 缓存
ASP.NET Core 会话状态(Session State)
存储内容示例:

图中,
第 1 项为浏览器 A 中,在 Session 中设置键 count 值为 3 的结果;
第 3 项为浏览器 B 中,在 Session 中设置键 count 值为 1 的结果;
而第 2 项为设置 Cache 键 count 值为 5 的结果。
ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:
内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache
SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache
MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache
Nuget 安装:Microsoft.Extensions.Caching.SqlServer
执行 .NET Core CLI 命令,在数据库中创建表“TestCache”
dotnet sql-cache create "数据库连接字符串" dbo TestCache
若提示
找不到 "dotnet sql-cache" 命令,请运行以下命令进行安装
则运行
dotnet tool install --global dotnet-sql-cache
表和索引创建成功提示:
Table and index were created successfully.
表结构:
在 Startup.cs 文件的方法 ConfigureServices() 中添加:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "数据库连接字符串";
options.SchemaName = "dbo";
options.TableName = "TestCache";
});
在控制器中注入 IDistributedCache:
public class TestController : Controller
{
private readonly IDistributedCache cache;
public TestController(IDistributedCache cache)
{
this.cache = cache;
}
public IActionResult Index()
{
string k = "count";
int v = Convert.ToInt32(cache.GetString(k));
v++;
cache.SetString(k, v.ToString());
return Content(v.ToString());
}
}
结果:
更多用法详见官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.0
若要实现将 Session 保存至 SQL Server 中,参此文:https://xoyozo.net/Blog/Details/aspnetcore-session-sql
ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:
内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache
SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache
MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache
Nuget 安装:Microsoft.Extensions.Caching.StackExchangeRedis
在 Startup.cs 文件的方法 ConfigureServices() 中添加:
services.AddStackExchangeRedisCache(options =>
{
// 连接字符串
options.Configuration = "192.168.111.134,password=aW1HAyupRKmiZn3Q";
// 键名前缀
options.InstanceName = "xoyozo_";
});在控制器中注入 IDistributedCache:
public class TestController : Controller
{
private readonly IDistributedCache cache;
public TestController(IDistributedCache cache)
{
this.cache = cache;
}
public IActionResult Index()
{
string k = "count";
int v = Convert.ToInt32(cache.GetString(k));
v++;
cache.SetString(k, v.ToString());
return Content(v.ToString());
}
}结果:

更多用法详见官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-3.0
注:.NET 6 已不支持 Redis on Windows 3.0。
经过以上配置,Session 也会保存到 Redis 中,键名是 前缀_Guid 格式。
关于 Session,参此文:https://xoyozo.net/Blog/Details/aspnetcore-session-redis
ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:
内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache
SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache
MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache
本文介绍内存缓存
Memory Caching
1.新建一个 ASP.NET Core 项目,选择 Web 应用程序,将身份验证 改为 不进行身份验证。
2.添加引用
Install-Package Microsoft.Extensions.Caching.Memory
3.使用
在 Startup.cs 中 ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
// Add framework services.
services.AddMvc();
}然后在
public class HomeController : Controller
{
private IMemoryCache _memoryCache;
public HomeController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public IActionResult Index()
{
string cacheKey = "key";
string result;
if (!_memoryCache.TryGetValue(cacheKey, out result))
{
result = $"LineZero{DateTime.Now}";
_memoryCache.Set(cacheKey, result);
}
ViewBag.Cache = result;
return View();
}
}这里是简单使用,直接设置缓存。
我们还可以加上过期时间,以及移除缓存,还可以在移除时回掉方法。
过期时间支持相对和绝对。
下面是详细的各种用法。
public IActionResult Index()
{
string cacheKey = "key";
string result;
if (!_memoryCache.TryGetValue(cacheKey, out result))
{
result = $"LineZero{DateTime.Now}";
_memoryCache.Set(cacheKey, result);
//设置相对过期时间2分钟
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(2)));
//设置绝对过期时间2分钟
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(2)));
//移除缓存
_memoryCache.Remove(cacheKey);
//缓存优先级 (程序压力大时,会根据优先级自动回收)
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.NeverRemove));
//缓存回调 10秒过期会回调
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromSeconds(10))
.RegisterPostEvictionCallback((key, value, reason, substate) =>
{
Console.WriteLine($"键{key}值{value}改变,因为{reason}");
}));
//缓存回调 根据Token过期
var cts = new CancellationTokenSource();
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.AddExpirationToken(new CancellationChangeToken(cts.Token))
.RegisterPostEvictionCallback((key, value, reason, substate) =>
{
Console.WriteLine($"键{key}值{value}改变,因为{reason}");
}));
cts.Cancel();
}
ViewBag.Cache = result;
return View();
}Distributed Cache Tag Helper
在 ASP.NET Core MVC 中有一个 Distributed Cache 我们可以使用。
我们直接在页面上增加 distributed-cache 标签即可。
<distributed-cache name="mycache" expires-after="TimeSpan.FromSeconds(10)">
<p>缓存项10秒过期-LineZero</p>
@DateTime.Now
</distributed-cache>
<distributed-cache name="mycachenew" expires-sliding="TimeSpan.FromSeconds(10)">
<p>缓存项有人访问就不会过期,无人访问10秒过期-LineZero</p>
@DateTime.Now
</distributed-cache>这样就能缓存标签内的内容。
完整操作步骤如下:
安装 NuGet 包:
Microsoft.AspNet.Web.Optimization打开
Views目录(如果是应用于区域,则为区域的Views目录)中的 web.config,在<namespaces />节点中添加<add namespace="System.Web.Optimization" />在
App_Start目录中创建类文件BundleConfig.cs,更改其命名空间为应用程序的默认命名空间(即移除.App_Start),创建方法:public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/虚拟路径(不能有点)").Include("~/CSS文件路径")); bundles.Add(new ScriptBundle("~/虚拟路径(不能有点)").Include("~/JS文件路径")); }虚拟路径应避免与页面访问路径相同。Include 可包含多个文件,效果是合并输出,注意引用的顺序。
打开
Global.asax,在Application_Start()事件中添加代码BundleTable.EnableOptimizations = true; // 该设置使在开发模式中实现压缩代码,不设置则仅在发布后压缩代码 BundleConfig.RegisterBundles(BundleTable.Bundles);视图页面中引用样式表或脚本
@Styles.Render("~/CSS虚拟路径") @Scripts.Render("~/JS虚拟路径")使用 Render 的好处是,ASP.NET 会自动给引用地址加上参数,可在更改脚本或样式表内容后更改这些参数使浏览器缓存立即失效。
如果你的项目中已经安装并使用 Bundle,那么只需要参考第 4 步,将 BundleTable 的 EnableOptimixations 设为 true。
以下是一些常见异常的解决方法:
The name 'Styles' does not exist in the current context
The name 'Scripts' does not exist in the current context
解决:参步骤 2。
引用的样式表或脚本不存在(报 404 错误)
解决:步骤 3 中的虚拟路径不规范。
前提:
若需获取用户 unionid,则小程序必须已绑定到微信开放平台。
小程序调用 wx.login(),将 code 发送到开发者服务器
开发者服务器请求微信接口 code2Session,获得 session_key、openid,有机会获得 unionid(参 UnionID 机制说明)。因此无需任何用户授权即可获取 openid
访问须要已获取用户信息的页面时,可通过小程序端使用 button + getUserInfo 的方式请求用户授权
访问须要已获取手机号码的页面时,可通过小程序端使用 button + getPhoneNumber 的方式请求用户授权
code2session、getUserInfo、getPhoneNumber 等接口返回数据存入数据库 dt_weapp_user
服务端的任何接口均返回口令状态包(含自定义会话口令等信息),小程序端应保存于 storage
请求 getUserInfo 后应判断 detail.errMsg 是否为 getUserInfo:ok,请求 getPhoneNumber 后应判断 detail.errMsg 是否为 getPhoneNumber:ok
授权窗口的弹出情况参此文
口令状态包是用来传递到客户端用来标识用户唯一凭证的,包含字段:会话口令(自定义用户凭证)、会话口令有效时间(秒)、是否已获取 unionid 或昵称(视业务需求)、是否已获取手机号码、uid(可选),以及其他用来标识业务身份字段。服务端可根据会话口令从数据库中获取该用户的所有已知信息。
一般情况下,当已获取手机号码时,uid 必有值,否则,uid 必为空。因此 uid 不是必须传递到客户端的。
通过 code2Session 获得的 session_key、以及 openid、unionid、手机号码等机密信息不允许包含在口令状态包中并缓存在客户端,客户端需要用到手机号码时单独调用接口获取。
若业务不要求以手机号码作为用户唯一标识,那么口令状态包中不需要包含是否已获取手机号码,仅 uid 即可。在客户端访问须要业务用户登录的页面时,也仅判断 uid 有值即可。
流程图:

为更好地适应 2017.7.19 发布的《小程序内用户帐号登录规范调整和优化建议》,开发者服务器提供的所有业务逻辑接口的返回值中都应包含口令状态包,约定有以下相关的返回值和处理动作(返回值按个人喜好来定):
| 口令状态 | 接口返回 | ASP.NET Web API 语句 | 处理动作 |
| access_token 空或失效 | 401 状态码 | return Unauthorized(); | login() + code2Session,获取 openid,生成 access_token |
| access_token 有效,但未获取 uniond 或用户信息 | 401 状态码,http 头 WWW-Authenticate 中标注 getUserInfo | return Unauthorized(new AuthenticationHeaderValue("getUserInfo")); | getUserInfo() |
| access_token 有效,但未获取手机号码(即未找到业务用户) | 401 状态码,http 头 WWW-Authenticate 中标注 getPhoneNumber | return Unauthorized(new AuthenticationHeaderValue("getPhoneNumber")); | getPhoneNumber() |
WWW-Authenticate 有大小写的问题,千万别入坑,参:https://xoyozo.net/Blog/Details/header-www-authenticate
返回内容是根据业务逻辑在服务端决定的,客户端在处理每个接口返回值时对返回内容作相应的处理即可。