博客 (128)

使用 JS 根据屏幕宽度来计算页面尺寸和字体大小并不是一个好办法。

rem 单位是跟随网页根元素的 font-size 改变而自动改变的,是一个相对的长度单位,非常适合在不同手机界面上自适应屏幕大小。 


一般的手机浏览器的默认字体大小为 16px。即:

:root { font-size: 16px; } /* 在 HTML 网页中,:root 选择器相当于 html */

也就是说,如果我定义一个宽度为 1rem,那么它的实际宽度为 16px。反过来说,如果设计稿宽度为 1000px,那么相当于 1000÷16=62.5‬rem。因此,我们设置一个 62.5rem 的宽度,即可正常显示 1000px 的设计效果。


为了适应不同屏幕尺寸的手机,只需按比例换算更改 :root 的 font-size 即可。这个比例是由“窗口宽度 ÷ 设计稿宽度”得到的,姑且称它为“窗设比”。

以 iPhone X 逻辑宽度 375px 为例,设计稿宽度 1000px 时,窗设比为:0.375。:root 的 font-size 将会被重置为 16 * 0.375 = 6px。上面的 62.5rem 宽度将对应 iPhone X 宽度为 62.5 * 6 = 375px,正好是屏幕逻辑宽度。


根据这个思路,理论上,我们只需要使用 CSS 将 :root 的 font-size 设置为 1px,然后使用 JS 重置为与“窗设比”相乘的积(本例中将被重置为 0.375px)。这样,我们可以不通过换算,只需要更改单位,将设计稿中的 500px 直接写入到 CSS 为 500rem,即可实现在 iPhone X 上显示逻辑宽度为(500 * 0.375 =)187.5px,即设计稿中的 1/2 宽度对应到屏幕上 1/2 的宽度。


实际上,部分安卓手机(如华为某旗舰机)不支持 :root 的 font-size 小于 12px,其它一些浏览器也会出现小于 12px 的文字以 12px 显示。


为了避免在任何环节出现小于 12px 的 font-size 值,且不增加设计稿尺寸到 CSS 数值的换算难度,我们设计了以下思路:

  1. 约定“设样比(设计稿的 px 值与 CSS 的 rem 值的比)”为 100;

  2. 使用 JS 将 :root 的 font-size 重置为“设样比”与“窗设比(窗口宽度 ÷ 设计稿宽度)”的乘积;

  3. 计算 CSS 时的 rem 值只需从设计稿中获取 px 值再除以“设样比”100 即可。 


这样做的另一个好处是,不用要求设计师必须按多少尺寸来设计,当然按主流尺寸来建议是可行的。


完整代码(jQuery 版):

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>Index</title>
    <style>
        body { margin: 0; text-align: center; }
        #app { margin: 0 auto; background-color: #EEE; display: none; }
        /* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
        .whole { background-color: #D84C40; width: 10rem; }
        .half { background-color: #3296FA; width: 5rem; }
        .half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
    </style>
</head>
<body>
    <div id="app">
        <div class="whole">100%</div>
        <div class="half">50%</div>
        <div class="half2">50%</div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        // [函数] 重置尺寸
        function fn_resize() {
            // 设计稿宽度(px)
            var designsWidth = 1000;
            // 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
            var px2rem = 100;
            // 限制 #app 的最大宽度为设计稿宽度
            $('#app').css('max-width', designsWidth).css('min-height', $(window).height());
            // 重置 :root 的 font-size
            var appWidth = Math.min($(window).width(), designsWidth);
            $(':root').css('font-size', px2rem * appWidth / designsWidth);
            $('#app').show();
        }
        // 页面加载完成后重置尺寸
        $(fn_resize);
        // 改变窗口大小时重置尺寸
        $(window).resize(fn_resize);
    </script>
</body>
</html>

完整代码(Vue2 版):

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>Index</title>
    <style>
        body { margin: 0; text-align: center; }
        #app { margin: 0 auto; background-color: #EEE; }
        /* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
        .whole { background-color: #D84C40; width: 10rem; }
        .half { background-color: #3296FA; width: 5rem; }
        .half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
    </style>
</head>
<body>
    <div id="app" v-bind:style="{ maxWidth: designsWidth + 'px', minHeight: appMinHeight + 'px' }" style="display: none;" v-show="appShow">
        <div class="whole">100%</div>
        <div class="half">50%</div>
        <div class="half2">50%</div>
        <div>appWidth: {{ appWidth }}</div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                // 设计稿宽度(px)
                designsWidth: 1000,
                // 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
                px2rem: 100,
                // #app 的 width
                appWidth: 0, // 勿改
                appMinHeight: 0, // 勿改
                appShow: false, // 勿改
            },
            mounted: function () {
                // 页面加载完成后重置尺寸
                this.fn_resize();
                const that = this;
                // 改变窗口大小时重置尺寸
                window.onresize = () => {
                    return (() => {
                        console.log('RUN window.onresize()');
                        that.fn_resize();
                    })();
                };
            },
            watch: {
                // 侦听 appWidth 更改 root 的 font-size
                appWidth: function () {
                    console.log('RUN watch: appWidth');
                    var root = document.getElementsByTagName("html")[0];
                    root.style.fontSize = (this.px2rem * this.appWidth / this.designsWidth) + 'px';
                    this.appShow = true;
                }
            },
            methods: {
                fn_resize: function () {
                    console.log('RUN methods: fn_resize()');
                    this.appWidth = Math.min(document.body.clientWidth, this.designsWidth);
                    this.appMinHeight = document.documentElement.clientHeight;
                }
            }
        });
    </script>
</body>
</html>

完整代码(Vue3 版):

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
    <title>Index</title>
    <style>
        body { margin: 0; text-align: center; }
        #app > div { display: none; margin: 0 auto; background-color: #EEE; }
        /* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
        .whole { background-color: #D84C40; width: 10rem; }
        .half { background-color: #3296FA; width: 5rem; }
        .half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
    </style>
</head>
<body>
    <div id="app">
        <div style="display: none;" v-bind:style="{ maxWidth: designsWidth + 'px', minHeight: appMinHeight + 'px', display: appShow ? 'block' : 'none' }">
            <div class="whole">100%</div>
            <div class="half">50%</div>
            <div class="half2">50%</div>
            <div>appWidth: {{ appWidth }}</div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
    <script>
        const app = Vue.createApp({
            data: function () {
                return {
                    // 设计稿宽度(px)
                    designsWidth: 1000,
                    // 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
                    px2rem: 100,
                    // #app 的 width
                    appWidth: 0, // 勿改
                    appMinHeight: 0, // 勿改
                    appShow: false, // 勿改
                }
            },
            mounted: function () {
                // 页面加载完成后重置尺寸
                this.fn_resize();
                const that = this;
                // 改变窗口大小时重置尺寸
                window.onresize = () => {
                    return (() => {
                        console.log('RUN window.onresize()');
                        that.fn_resize();
                    })();
                };
            },
            watch: {
                // 侦听 appWidth 更改 root 的 font-size
                appWidth: function () {
                    console.log('RUN watch: appWidth');
                    var root = document.getElementsByTagName("html")[0];
                    root.style.fontSize = (this.px2rem * this.appWidth / this.designsWidth) + 'px';
                    this.appShow = true;
                }
            },
            methods: {
                fn_resize: function () {
                    console.log('RUN methods: fn_resize()');
                    this.appWidth = Math.min(document.body.clientWidth, this.designsWidth);
                    this.appMinHeight = document.documentElement.clientHeight;
                }
            }
        });
        const vm = app.mount('#app');
    </script>
</body>
</html>


示例中 CSS 初始 :root 的 font-size 为 16px(一个较小值,防止页面加载时瞬间出现大号文字影响用户体验),经过 fn_resize 后,:root 的 font-size 被设置为(100 * 375 / 1000 =)37.5px(iPhone X 中),那么宽度为 1000px 的设计稿中的 500px 换算到 CSS 中为 5rem,也即 37.5 * 5 = 187.5px,就是 iPhone X 的屏幕宽度的一半。

示例中 id 为 app 的 div 是用来在 PC 浏览器中限制页面内容最大宽度的(类似微信公众号发布的文章),如果网页不需要在 PC 端显示,jQuery 版代码中的 $('#app').width() 可以用 $(window).width() 来代替。

这个 div#app 一般设计有背景色,用于在宽度超过设计稿的设备上显示时区别于 body 的背景。但是当网页内容不超过一屏时,div#app 高度小于窗口,示例中与 appMinHeight 相关的代码就是为了解决这个问题。

示例中 div#app 隐藏/显示相关代码用于解决在页面加载初期由于 font-size 值变化引起的一闪而过的排版错乱。

image.png


最后补充一点,如果改变窗口大小时涉及执行耗时的操作,为避免页面卡顿,可以参考这篇文章添加函数防抖:https://xoyozo.net/Blog/Details/js-function-anti-shake

xoyozo 6 年前
9,532


引用

jQuery、moment.js、daterangepicker


例子

$('.x_dates').daterangepicker({
    "timePicker": false, // 是否显示时间
    //"dateLimit": {
    //    "days": 7 // 可选中的最大区间(天)
    //},
    "ranges": { // 快捷栏
        "今天": [moment(), moment()],
        "昨天": [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
        "最近 7 天": [moment().subtract(6, 'days'), moment()],
        "最近 30 天": [moment().subtract(29, 'days'), moment()],
        "本月": [moment().startOf('month'), moment().endOf('month')],
        "上个月": [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
    },
    startDate: daterangepicker_startDate, // moment(),
    endDate: daterangepicker_endDate, // moment(),
    autoUpdateInput: true,
    "locale": {
        "direction": "ltr",
        "format": "YYYY-MM-DD", // YYYY-MM-DD HH:mm
        "separator": " 至 ",
        "applyLabel": "确定",
        "cancelLabel": "取消",
        "fromLabel": "From",
        "toLabel": "To",
        "customRangeLabel": "自定义",
        "daysOfWeek": ["日", "一", "二", "三", "四", "五", "六"],
        "monthNames": ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
        "firstDay": 1
    }
}, function (start, end, label) {
    //console.log('New date range selected: ' + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD') + ' (predefined range: ' + label + ')');
    fn_daterangepicker_changed(start.format('YYYY-MM-DD'), end.format('YYYY-MM-DD'))
});


官网(含配置工具)

http://www.daterangepicker.com/


GitHub

https://github.com/dangrossman/daterangepicker


配置工具

下载的包中的 demo.html


Demo

https://awio.iljmp.com/5/drpdemo


xoyozo 6 年前
5,858
返回状态ASP.NET MVCASP.NET CoreASP.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 JSONreturn Json(object);

return Json(T); // 强制 JSON

return Ok(T); // 请求时可指定 Content-Type

return Json(T); // 强制 JSON

return Ok(T); // 请求时可指定 Content-Type

200 JaveScriptreturn 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();


xoyozo 6 年前
5,841

对于不同场景下 WebP 的使用,我们总结了一些解决方案,如下:

 1、若使用场景是浏览器,可以:

JavaScript 能力检测,对支持 WebP 的用户输出 WebP 图片(https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_for_webp

使用 WebP 支持插件:WebPJS:http://webpjs.appspot.com,下载 webpjs-0.0.2.min.js


 2、若使用场景是 App,可以:

Android 4.0 以下 WebP 解析库(https://github.com/alexey-pelykh/webp-android-backport

iOS WebP 解析库(https://github.com/carsonmcdonald/WebP-iOS-example


 3、转换工具:

智图(http://zhitu.tencent.com

iSparta(http://isparta.github.io/



阿里云 OSS 格式转换:https://help.aliyun.com/document_detail/44703.html

腾讯云数据万象格式转换:https://cloud.tencent.com/document/product/460/36543

七牛:https://developer.qiniu.com/dora/api/1279/basic-processing-images-imageview2


x
转自 xiangzhihong 6 年前
6,457

Discuz! 的“词语过滤”支持替换功能,并且借用替换的思想实现禁止发布。

添加关键词举例:

a=b
a 将被替换成 b
a={BANNED}包含 a 的内容将被禁止发布
a={MOD}包含 a 的内容将进入人工审核通道
aa 将被替换成 **

另外注意几个要点:

  • 替换前的内容可以使用限定符 {x} 以限定相邻两字符间可忽略的文字,x 是忽略的字节数。如 "a{1}s{2}s"(不含引号) 可以过滤 "ass" 也可过滤 "axsxs" 和 "axsxxs" 等等。对于中文字符,若使用 GBK、Big-5 版本,每个中文字符相当于 2 个字节;若使用 UTF-8 版本,每个中文字符相当于 3 个字节。

    不良词语如果以"/"(不含引号)开头和结尾则表示格式为正则表达式,这时替换内容可用"(n)"引用正则中的子模式,如"/1\d{10}([^\d]+|$)/"替换为"手机(1)"。

  • 不支持通配符。

  • 系统在发帖时判断并替换过滤词语,数据库中保存的是替换后的内容。因此新添加的词语并不会对旧帖产生影响。

该功能对应数据库表:pre_common_word

xoyozo 6 年前
13,706

image.png

不支持当前所选音轨的文件格式,因此无法播放视频。请尝试播放其它音轨,确认其是否支持。


打开“套件中心”,打开右上角“设置”,添加“套件来源”:http://packages.synocommunity.com/,名称如:SynoCommunity,确定。

切换到“常规”选项卡,将“信任层级”改为至少“Synology Inc. 和信任的发行者”。否则会提示以下错误:

安装 [ffmpeg] 失败。此套件并非由 Synology Inc. 发布。

在“套件中心”左侧会出现“社群”,找到“ffmpeg”安装。

image.png

image.pngimage.png

如遇下载失败,多尝试几次。

或直接从官方网站下载 .spk 包:https://synocommunity.com/package/ffmpeg

在“套件中心”“手动安装”即可。

xoyozo 6 年前
16,649

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()

xoyozo 7 年前
8,633

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());
    }
}

结果:

image.png

更多用法详见官方文档: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

xoyozo 7 年前
7,196

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>

这样就能缓存标签内的内容。


L
转自 LineZero 7 年前
9,647

image.png

使用 myssl.com 检测证书状态,显示握手失败(No FS No SNI):

image.png

发现 XP 上的 IE6 和 IE8 均无法访问该站点,原因是 XP 不支持 FS,不支持 SNI。

可以尝试在 IIS 的站点的“绑定”中更改“需要服务器名称指示”来实现正常访问。

步骤参阅:https://xoyozo.net/Blog/Details/wxpay-notify-url-https

当然,前提是服务器上必须已启用相关的协议版本和加密方式(按需启用),建议使用 IISCrypto

image.png

xoyozo 7 年前
8,682