HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

Vue打包项目报错 Uncaught SyntaxError: Unexpected token ‘<‘ 的解决方法

打包 vue.js

打包时路径配置错误
在vue.config.js中
publicPath的默认值为 '/'
把publicPath的值设为“./”就可以了

publicPath#
Type: string

Default: '/'

部署应用包时的基本 URL。用法和 webpack 本身的 output.publicPath 一致,
但是 Vue CLI 在一些其他地方也需要用到这个值,所以请始终使用 publicPath 而不要直接修改 webpack 的 output.publicPath。

默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,
例如 https://www.my-app.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。
例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 publicPath 为 /my-app/。

这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),
这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,
也可以用在类似 Cordova hybrid 应用的文件系统中。

继续阅读 »

打包时路径配置错误
在vue.config.js中
publicPath的默认值为 '/'
把publicPath的值设为“./”就可以了

publicPath#
Type: string

Default: '/'

部署应用包时的基本 URL。用法和 webpack 本身的 output.publicPath 一致,
但是 Vue CLI 在一些其他地方也需要用到这个值,所以请始终使用 publicPath 而不要直接修改 webpack 的 output.publicPath。

默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上,
例如 https://www.my-app.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。
例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 publicPath 为 /my-app/。

这个值也可以被设置为空字符串 ('') 或是相对路径 ('./'),
这样所有的资源都会被链接为相对路径,这样打出来的包可以被部署在任意路径,
也可以用在类似 Cordova hybrid 应用的文件系统中。

收起阅读 »

【ChatGPT】将Chat GPT接入你的uni-app中

OpenAI ChatGPT uni_im uniCloud

更好的排版请访问:我的语雀工作空间我的知乎专栏我的稀土掘金

注意:实际项目使用时,务必添加内容安全检测,文字检测!!! 推荐使用:uni-sec-check

在uni-im中集成OpenAI

本文将介绍如何在uni-im中集成OpenAI API,以便为您的聊天应用程序提供更加智能和高效的聊天服务。通过集成OpenAI API,您可以利用各种自然语言处理和机器学习技术,如文本生成、语言翻译、图像分类等,来增强您的应用程序的功能和性能。

OK,Talk is cheap. Show me the code.

步骤一:注册OpenAI账号并获取API密钥

首先,您需要有OpenAI网站账号,并获取API密钥。网上有很多相关教程

访问 Account API Keys - OpenAI API ,点击这里的 Create new secret key,创建一个新的 key,并保存备用。

步骤二:创建uni-im应用程序

接下来,我们在HBuilder X中创建一个uni-im项目,插件地址:https://ext.dcloud.net.cn/plugin?name=uni-im,并在开发者中心中启用UniPush2.0服务。

在此示例中我们直接使用uni-im的示例项目来进行。

1、在插件市场中点击【使用 HBuilderX 导入示例项目】

2、在HBuilder X中创建项目

3、绑定uniCloud服务空间

4、部署云端资源

5、开始部署

等待自动部署,如果是新服务空间一路同意。缺表就创建。如果是和其他项目共用一个服务空间。请谨慎操作

6、在开发者后台开启UniPush


7、跑起来


没有报错就成功了。[GtPush] ["already connected"]

步骤三:在UniCloud中集成OpenAI API

1、新建云函数

2、修改云函数Nodejs版本

因为let's encrypt根证书过期,nodejs8版本请求使用了let's encrypt证书的网站时会出现 certificate has expired所以需要将云函数升级到nodejs12。相关文档: 云函数通过https访问其他服务器时出现“certificate has expired”

3、调用OpenAI API

OpenAI接口文档地址:https://platform.openai.com/docs/api-reference/completions uniCloud访问其他HTTP服务文档:https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#httpclient

'use strict';  
//OpenAI SDK、uniCloud.httpclient.request方式 二选一。  
// const {  
//  Configuration,  
//  OpenAIApi  
// } = require("openai");  

exports.main = async (event, context) => {  
    //event为客户端上传的参数  
    console.log('event : ', event)  
    // const configuration = new Configuration({  
    //  apiKey: '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',  
    // });  
    // const openai = new OpenAIApi(configuration);  
    // const {  
    //  data: {  
    //      choices  
    //  },  
    //  status,  
    //  statusText  
    // } = await openai.createCompletion({  
    //  model: "text-davinci-003",  
    //  prompt: `input:${event.body}?  
    //   output:`,  
    //  max_tokens: 300,  
    //  temperature: 1,  
    //  stop: ['output:']  
    // });  
    const {  
        data: {  
            choices  
        },  
        status,  
        statusText  
    } = await uniCloud.httpclient.request('https://api.openai.com/v1/completions', {  
        method: 'POST',  
        data: {  
            // GPT-3 模型。详细介绍请参考:https://platform.openai.com/docs/models/overview  
            model: "text-davinci-003",  
            prompt: `input:${event.body}?  
      output:`,  
            max_tokens: 300,  
            temperature: .6,  
            stop: ['output:']  
        },  
        headers: {  
            Authorization: `Bearer ${YOUR_API_KEY}`  
        },  
        timeout: 10000,  
        contentType: 'json', // 指定以application/json发送data内的数据  
        dataType: 'json' // 指定返回值为json格式,自动进行parse  
    })  
    //返回数据给客户端  
    return {  
        data: choices,  
        errCode: status,  
        errMsg: statusText  
    }  
};

4、测试一下

a、首先在云函数右击,配置运行测试参数

b、本地运行云函数

c、Bingo~

OpenAI的对接就这么简单。接下来我们来改造一下Uni-im

步骤四:在Uni-IM中集成Chat-GPT机器人。

1、创建Chat-GPT机器人账号


Chrome devtools-Applocation中找到“机器人”的uid63eb5550819ce84ffc2df8c5

当然,更推荐你去uniCloud 控制台-云数据库 中查看uni-id-users表中的_id字段.

2、在公共模块中添加uid

3、调用ChatGPT接口回复用户信息

这一步我们将改造uni-im-co云对象,在用户发送消息的方法中请求OpenAI接口,并将接口返回的消息回复给用户。uni-im-co云对象的sendMsg是用户发送消息,并存储到数据库的方法。
我们在uni-im-co云对象中ctrl+G/control+G定位代码到435

1、第一步

// 修改文件:uni-im-co/index.obj.js:435  

// 请求公共模块中的ChatGPT _uid常量  
const isChatGPT = uniImConfig.config('ChatGPT_uid')  
if(isChatGPT === to_uid){  
    try{  
        // 请求chatGPT云函数  
        const {result: { data: openAIResp }} = await uniCloud.callFunction({  
            name:'ChatGPT',  
            data:{  
                body  
            }  
        })  
        // 拼接消息  
        const allChatData = openAIResp.reduce((prev, {text})=> prev + text, '')  
        // 因为这一步要模拟ChatGPT给用户发消息,所以调换一下发送人和接受人的uid。  
        const tempParams = { ...params,  
        ...{  
            from_uid: to_uid,  
            to_uid: from_uid,  
            body: allChatData,  
            client_create_time: +new Date,  
            original_from_uid: to_uid // 这个字段用来递归调用时区分当前发送者uid  
        }};  
        // 递归调用云对象中的sendMsg方法  
        uniCloud.importObject('uni-im-co').sendMsg(tempParams, context);  
    } catch (error){  
        console.log('error boredape:>>>>>>>>>>>> ', error);  
    }  
}

1、兼容发送者uid

刚才我们在递归调用sendMsg方法时,传递了一个original_from_uid字段。这个字段是用来区分当前发送者uid的。我们在sendMsg方法参数中兼容处理一下它(我们在uni-im-co云对象中ctrl+G/control+G定位代码到248行找到sendMsg方法)

// 文件位置:uni-im-co/index.obj.js:248  
const {  
            to_uid,  
            group_id,  
            body,  
            type,  
            isRetries,  
            appId,  
            original_from_uid // 新增  
        } = params  
        //发送者身份id  
        const from_uid = this.uid || original_from_uid; // 修改

4、大功告成!让我们来跟ChatGPT进行第一次正式约会。

1、创建一个自己的账号

2、手动跳转到chat页面

目前我们还不能直接和机器人对话。那就让我们主动一点在浏览器中输入房间号:(此处的user_id就是ChatGPTuid)
http://localhost:8081/#/uni_modules/uni-im/pages/chat/chat?user_id=63eb5550819ce84ffc2df8c5

emmmmm~报错了。


看来是uniPush不支持本地调试的问题,我们部署一下


如果有模块冲突请确认是否替换.

3、OK。我们部署完之后切换使用云端云函数

d、完成后重新运行一下项目。

EMMMMMMMMM~这又是什么错呢?

4、我们查一下云函数的运行日志


发现这个是因为OpenAI超时导致的。云函数/云对象默认的超时时间时5S,这对于OpenAI来说很难在这么短时间内回复。

5、那我们修改一下ChatGPTuni-im-co这两个云函数和云对象的超时时间

最大只支持10S

6、uni-im-co云对象在递归时会走云对象的拦截器_before进行鉴权。递归调用没有`this.clientInfo参数。所以鉴权失败,无法发送消息返回给用户。

我们来修改一下uni-im-co云对象的拦截器。判断当前云对象的调用环境。如果是云函数调用的则不进行鉴权。定位代码到uni-im-co/index.obj.js:35

        if (needLoginMethodName.includes(this.getMethodName())) {  
            let res = await this.uniIdCommon.checkToken(this.clientInfo.uniIdToken)  
            // console.log('checkToken', JSON.stringify(res));  
                        // 判断当前调用的云对象方法是 ‘sendMsg’ 并且 是云函数调用的(递归)  
            if(this.getMethodName() === 'sendMsg' && this.getClientInfo().source === 'function'){} // 新增  
            else if (res.errCode ) {  
                throw new Error(res.errCode)  
            }  
            this.uid = res.uid  
        }

再来试一把

The END!

以上就是所有我们使用UniIM集成OpenAI的全部步骤。使用UniCloud快速对接OpenAI,封装属于自己的ChatGPT

稍后我会上传Demo工程源码,不过强烈推荐您自己动手哦。能让您更加了解UniCloudUniIM。真的是超棒的框架!

如果您觉得我的文章不错。请在左下方点赞,并关注我哦,如果有新文章会第一时间给您推送。您的支持是对我生发爆肝最大的动力。
如果您还想让我帮您体验使用Uni-app/UniCloud集成第三方好玩的SDK,请在下方评论区留言哦。

继续阅读 »

更好的排版请访问:我的语雀工作空间我的知乎专栏我的稀土掘金

注意:实际项目使用时,务必添加内容安全检测,文字检测!!! 推荐使用:uni-sec-check

在uni-im中集成OpenAI

本文将介绍如何在uni-im中集成OpenAI API,以便为您的聊天应用程序提供更加智能和高效的聊天服务。通过集成OpenAI API,您可以利用各种自然语言处理和机器学习技术,如文本生成、语言翻译、图像分类等,来增强您的应用程序的功能和性能。

OK,Talk is cheap. Show me the code.

步骤一:注册OpenAI账号并获取API密钥

首先,您需要有OpenAI网站账号,并获取API密钥。网上有很多相关教程

访问 Account API Keys - OpenAI API ,点击这里的 Create new secret key,创建一个新的 key,并保存备用。

步骤二:创建uni-im应用程序

接下来,我们在HBuilder X中创建一个uni-im项目,插件地址:https://ext.dcloud.net.cn/plugin?name=uni-im,并在开发者中心中启用UniPush2.0服务。

在此示例中我们直接使用uni-im的示例项目来进行。

1、在插件市场中点击【使用 HBuilderX 导入示例项目】

2、在HBuilder X中创建项目

3、绑定uniCloud服务空间

4、部署云端资源

5、开始部署

等待自动部署,如果是新服务空间一路同意。缺表就创建。如果是和其他项目共用一个服务空间。请谨慎操作

6、在开发者后台开启UniPush


7、跑起来


没有报错就成功了。[GtPush] ["already connected"]

步骤三:在UniCloud中集成OpenAI API

1、新建云函数

2、修改云函数Nodejs版本

因为let's encrypt根证书过期,nodejs8版本请求使用了let's encrypt证书的网站时会出现 certificate has expired所以需要将云函数升级到nodejs12。相关文档: 云函数通过https访问其他服务器时出现“certificate has expired”

3、调用OpenAI API

OpenAI接口文档地址:https://platform.openai.com/docs/api-reference/completions uniCloud访问其他HTTP服务文档:https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#httpclient

'use strict';  
//OpenAI SDK、uniCloud.httpclient.request方式 二选一。  
// const {  
//  Configuration,  
//  OpenAIApi  
// } = require("openai");  

exports.main = async (event, context) => {  
    //event为客户端上传的参数  
    console.log('event : ', event)  
    // const configuration = new Configuration({  
    //  apiKey: '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',  
    // });  
    // const openai = new OpenAIApi(configuration);  
    // const {  
    //  data: {  
    //      choices  
    //  },  
    //  status,  
    //  statusText  
    // } = await openai.createCompletion({  
    //  model: "text-davinci-003",  
    //  prompt: `input:${event.body}?  
    //   output:`,  
    //  max_tokens: 300,  
    //  temperature: 1,  
    //  stop: ['output:']  
    // });  
    const {  
        data: {  
            choices  
        },  
        status,  
        statusText  
    } = await uniCloud.httpclient.request('https://api.openai.com/v1/completions', {  
        method: 'POST',  
        data: {  
            // GPT-3 模型。详细介绍请参考:https://platform.openai.com/docs/models/overview  
            model: "text-davinci-003",  
            prompt: `input:${event.body}?  
      output:`,  
            max_tokens: 300,  
            temperature: .6,  
            stop: ['output:']  
        },  
        headers: {  
            Authorization: `Bearer ${YOUR_API_KEY}`  
        },  
        timeout: 10000,  
        contentType: 'json', // 指定以application/json发送data内的数据  
        dataType: 'json' // 指定返回值为json格式,自动进行parse  
    })  
    //返回数据给客户端  
    return {  
        data: choices,  
        errCode: status,  
        errMsg: statusText  
    }  
};

4、测试一下

a、首先在云函数右击,配置运行测试参数

b、本地运行云函数

c、Bingo~

OpenAI的对接就这么简单。接下来我们来改造一下Uni-im

步骤四:在Uni-IM中集成Chat-GPT机器人。

1、创建Chat-GPT机器人账号


Chrome devtools-Applocation中找到“机器人”的uid63eb5550819ce84ffc2df8c5

当然,更推荐你去uniCloud 控制台-云数据库 中查看uni-id-users表中的_id字段.

2、在公共模块中添加uid

3、调用ChatGPT接口回复用户信息

这一步我们将改造uni-im-co云对象,在用户发送消息的方法中请求OpenAI接口,并将接口返回的消息回复给用户。uni-im-co云对象的sendMsg是用户发送消息,并存储到数据库的方法。
我们在uni-im-co云对象中ctrl+G/control+G定位代码到435

1、第一步

// 修改文件:uni-im-co/index.obj.js:435  

// 请求公共模块中的ChatGPT _uid常量  
const isChatGPT = uniImConfig.config('ChatGPT_uid')  
if(isChatGPT === to_uid){  
    try{  
        // 请求chatGPT云函数  
        const {result: { data: openAIResp }} = await uniCloud.callFunction({  
            name:'ChatGPT',  
            data:{  
                body  
            }  
        })  
        // 拼接消息  
        const allChatData = openAIResp.reduce((prev, {text})=> prev + text, '')  
        // 因为这一步要模拟ChatGPT给用户发消息,所以调换一下发送人和接受人的uid。  
        const tempParams = { ...params,  
        ...{  
            from_uid: to_uid,  
            to_uid: from_uid,  
            body: allChatData,  
            client_create_time: +new Date,  
            original_from_uid: to_uid // 这个字段用来递归调用时区分当前发送者uid  
        }};  
        // 递归调用云对象中的sendMsg方法  
        uniCloud.importObject('uni-im-co').sendMsg(tempParams, context);  
    } catch (error){  
        console.log('error boredape:>>>>>>>>>>>> ', error);  
    }  
}

1、兼容发送者uid

刚才我们在递归调用sendMsg方法时,传递了一个original_from_uid字段。这个字段是用来区分当前发送者uid的。我们在sendMsg方法参数中兼容处理一下它(我们在uni-im-co云对象中ctrl+G/control+G定位代码到248行找到sendMsg方法)

// 文件位置:uni-im-co/index.obj.js:248  
const {  
            to_uid,  
            group_id,  
            body,  
            type,  
            isRetries,  
            appId,  
            original_from_uid // 新增  
        } = params  
        //发送者身份id  
        const from_uid = this.uid || original_from_uid; // 修改

4、大功告成!让我们来跟ChatGPT进行第一次正式约会。

1、创建一个自己的账号

2、手动跳转到chat页面

目前我们还不能直接和机器人对话。那就让我们主动一点在浏览器中输入房间号:(此处的user_id就是ChatGPTuid)
http://localhost:8081/#/uni_modules/uni-im/pages/chat/chat?user_id=63eb5550819ce84ffc2df8c5

emmmmm~报错了。


看来是uniPush不支持本地调试的问题,我们部署一下


如果有模块冲突请确认是否替换.

3、OK。我们部署完之后切换使用云端云函数

d、完成后重新运行一下项目。

EMMMMMMMMM~这又是什么错呢?

4、我们查一下云函数的运行日志


发现这个是因为OpenAI超时导致的。云函数/云对象默认的超时时间时5S,这对于OpenAI来说很难在这么短时间内回复。

5、那我们修改一下ChatGPTuni-im-co这两个云函数和云对象的超时时间

最大只支持10S

6、uni-im-co云对象在递归时会走云对象的拦截器_before进行鉴权。递归调用没有`this.clientInfo参数。所以鉴权失败,无法发送消息返回给用户。

我们来修改一下uni-im-co云对象的拦截器。判断当前云对象的调用环境。如果是云函数调用的则不进行鉴权。定位代码到uni-im-co/index.obj.js:35

        if (needLoginMethodName.includes(this.getMethodName())) {  
            let res = await this.uniIdCommon.checkToken(this.clientInfo.uniIdToken)  
            // console.log('checkToken', JSON.stringify(res));  
                        // 判断当前调用的云对象方法是 ‘sendMsg’ 并且 是云函数调用的(递归)  
            if(this.getMethodName() === 'sendMsg' && this.getClientInfo().source === 'function'){} // 新增  
            else if (res.errCode ) {  
                throw new Error(res.errCode)  
            }  
            this.uid = res.uid  
        }

再来试一把

The END!

以上就是所有我们使用UniIM集成OpenAI的全部步骤。使用UniCloud快速对接OpenAI,封装属于自己的ChatGPT

稍后我会上传Demo工程源码,不过强烈推荐您自己动手哦。能让您更加了解UniCloudUniIM。真的是超棒的框架!

如果您觉得我的文章不错。请在左下方点赞,并关注我哦,如果有新文章会第一时间给您推送。您的支持是对我生发爆肝最大的动力。
如果您还想让我帮您体验使用Uni-app/UniCloud集成第三方好玩的SDK,请在下方评论区留言哦。

收起阅读 »

强缓存与协商缓存(原文:https://www.jianshu.com/p/9c95db596df5/)

缓存的优点:

减少了不必要的数据传输,节省带宽
减少服务器的负担,提升网站性能
加快了客户端加载网页的速度
用户体验友好
缺点:
资源如果有更改但是客户端不及时更新会造成用户获取信息滞后,
如果老版本有bug的话,情况会更加糟糕。

一、强缓存

respone header 的cache-control,常见的设置是max-age public private no-cache no-store等
cache-control:max-age=31536000,public,immutable

max-age表示缓存的时间 单位为秒
public表示可以被浏览器和代理服务器缓存
immutable表示该资源永远不变,在没过缓存期时,
即使用户做了刷新操作,也不向服务器发起http请求,直接读取缓存。

强缓存总结

cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,
如果用户做了刷新操作,就向服务器发起http请求

cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200

cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,
即使用户做了刷新操作,也不向服务器发起http请求

cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,
只有在强缓存失效了才走协商缓存的,
设置了no-cache就不会走强缓存了,每次请求都回询问服务端。

cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。

二、协商缓存

协商缓存就是需要客户端和服务器两端进行交互的。
怎么设置协商缓存?
response header里面的设置
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT

etag:每个文件有一个,改动文件了就变了,就是个文件hash,每个文件唯一,
就像用webpack打包的时候,每个资源都会有这个东西,如: app.js打包后变为 app.c20abbde.js,加个唯一hash,也是为了解决缓存问题。
last-modified:文件的修改时间,精确到秒
也就是说,每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上,
服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,
和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified,
这时候对客户端来说,每次请求都是要进行协商缓存了,即:
发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期-->没过期-->返回304状态码-->客户端用缓存的老资源。
这就是一条完整的协商缓存的过程。

当然,当服务端发现资源真的过期的时候,会走如下流程:

发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期-->过期-->返回200状态码-->客户端如第一次接收该资源一样,记下它的cache-control中的max-age、etag、last-modified等。

所以协商缓存步骤总结:
请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。
如果资源没更改,返回304,浏览器读取本地缓存。
如果资源有更改,返回200,返回最新的资源。
补充一点,response header中的etag、last-modified在客户端重新向服务端发起请求时,会在request header中换个key名:
// response header
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT

// request header 变为
if-none-matched: '5c20abbd-e2e8'
if-modified-since: Mon, 24 Dec 2018 09:49:49 GMT

为什么要有etag?
你可能会觉得使用last-modified已经足以让浏览器知道本地的缓存副本是否足够新,
为什么还需要etag呢?HTTP1.1中etag的出现(也就是说,etag是新增的,为了解决之前只有If-Modified的缺点)
主要是为了解决几个last-modified比较难解决的问题:

一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),
这个时候我们并不希望客户端认为这个文件被修改了,而重新get;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),
if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

某些服务器不能精确的得到文件的最后修改时间。

继续阅读 »

缓存的优点:

减少了不必要的数据传输,节省带宽
减少服务器的负担,提升网站性能
加快了客户端加载网页的速度
用户体验友好
缺点:
资源如果有更改但是客户端不及时更新会造成用户获取信息滞后,
如果老版本有bug的话,情况会更加糟糕。

一、强缓存

respone header 的cache-control,常见的设置是max-age public private no-cache no-store等
cache-control:max-age=31536000,public,immutable

max-age表示缓存的时间 单位为秒
public表示可以被浏览器和代理服务器缓存
immutable表示该资源永远不变,在没过缓存期时,
即使用户做了刷新操作,也不向服务器发起http请求,直接读取缓存。

强缓存总结

cache-control: max-age=xxxx,public
客户端和代理服务器都可以缓存该资源;
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,
如果用户做了刷新操作,就向服务器发起http请求

cache-control: max-age=xxxx,private
只让客户端可以缓存该资源;代理服务器不缓存
客户端在xxx秒内直接读取缓存,statu code:200

cache-control: max-age=xxxx,immutable
客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,statu code:200 ,
即使用户做了刷新操作,也不向服务器发起http请求

cache-control: no-cache
跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,
只有在强缓存失效了才走协商缓存的,
设置了no-cache就不会走强缓存了,每次请求都回询问服务端。

cache-control: no-store
不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。

二、协商缓存

协商缓存就是需要客户端和服务器两端进行交互的。
怎么设置协商缓存?
response header里面的设置
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT

etag:每个文件有一个,改动文件了就变了,就是个文件hash,每个文件唯一,
就像用webpack打包的时候,每个资源都会有这个东西,如: app.js打包后变为 app.c20abbde.js,加个唯一hash,也是为了解决缓存问题。
last-modified:文件的修改时间,精确到秒
也就是说,每次请求返回来 response header 中的 etag和 last-modified,在下次请求时在 request header 就把这两个带上,
服务端把你带过来的标识进行对比,然后判断资源是否更改了,如果更改就直接返回新的资源,
和更新对应的response header的标识etag、last-modified。如果资源没有变,那就不变etag、last-modified,
这时候对客户端来说,每次请求都是要进行协商缓存了,即:
发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期-->没过期-->返回304状态码-->客户端用缓存的老资源。
这就是一条完整的协商缓存的过程。

当然,当服务端发现资源真的过期的时候,会走如下流程:

发请求-->看资源是否过期-->过期-->请求服务器-->服务器对比资源是否真的过期-->过期-->返回200状态码-->客户端如第一次接收该资源一样,记下它的cache-control中的max-age、etag、last-modified等。

所以协商缓存步骤总结:
请求资源时,把用户本地该资源的 etag 同时带到服务端,服务端和最新资源做对比。
如果资源没更改,返回304,浏览器读取本地缓存。
如果资源有更改,返回200,返回最新的资源。
补充一点,response header中的etag、last-modified在客户端重新向服务端发起请求时,会在request header中换个key名:
// response header
etag: '5c20abbd-e2e8'
last-modified: Mon, 24 Dec 2018 09:49:49 GMT

// request header 变为
if-none-matched: '5c20abbd-e2e8'
if-modified-since: Mon, 24 Dec 2018 09:49:49 GMT

为什么要有etag?
你可能会觉得使用last-modified已经足以让浏览器知道本地的缓存副本是否足够新,
为什么还需要etag呢?HTTP1.1中etag的出现(也就是说,etag是新增的,为了解决之前只有If-Modified的缺点)
主要是为了解决几个last-modified比较难解决的问题:

一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),
这个时候我们并不希望客户端认为这个文件被修改了,而重新get;
某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),
if-modified-since能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒);

某些服务器不能精确的得到文件的最后修改时间。

收起阅读 »

ios

iOS

ios

ios

同步资源失败,未得到同步资源的授权,请停止运行后重新运行,并注意手机上的授权提示

uniapp

系统版本号:10.0.16299
编译器版本:3.6.18(vue3)
fast启动模式
手机型号
:iqoo neo5
控制台截图


描述:多次开关手机开发者模式、usb调试;使用HBuilder自带的ADB进行真机运行;保持手机和电脑在同一个局域网下;
使用标准基座和自定义基座都无法解决该问题。

继续阅读 »

系统版本号:10.0.16299
编译器版本:3.6.18(vue3)
fast启动模式
手机型号
:iqoo neo5
控制台截图


描述:多次开关手机开发者模式、usb调试;使用HBuilder自带的ADB进行真机运行;保持手机和电脑在同一个局域网下;
使用标准基座和自定义基座都无法解决该问题。

收起阅读 »

百川旗舰版集成流程图

1.首先加入百川http://baichuan.taobao.com/,在阿里百川控制台创建应用获取appkey:

2.在阿里百川控制台"我的产品后台"中查看是否开通 “百川电商sdk” 和 “百川电商旗舰版” :

3.在https://suite.baichuan.taobao.com/suite2.htm?spm=a3c0d.8115090.0.0#/sdk上生成安全图片:
(使用V6版安全图片,android 需要上传包含包名和签名证书的apk, iOS只需要填写 bundleId;图片需另命名为yw_1222_baichuan.jpg)

继续阅读 »

1.首先加入百川http://baichuan.taobao.com/,在阿里百川控制台创建应用获取appkey:

2.在阿里百川控制台"我的产品后台"中查看是否开通 “百川电商sdk” 和 “百川电商旗舰版” :

3.在https://suite.baichuan.taobao.com/suite2.htm?spm=a3c0d.8115090.0.0#/sdk上生成安全图片:
(使用V6版安全图片,android 需要上传包含包名和签名证书的apk, iOS只需要填写 bundleId;图片需另命名为yw_1222_baichuan.jpg)

收起阅读 »

提一个路由改进建议

路由

目前的路由是没有分组的,如果一个项目几百个页面,在pages.json文件全部展示出来,找起来是非常麻烦的,而且路由匹配的速度应该也不快,可以设计路由分组,同模块下多个页面,可以在一个组下,例如下面这种php的写法,也方便在编辑器折叠,找起来也比较方便
//会员数据请求
Route::group('user/', function(){
//会员信息查询与更新
Route::group('handle/', function () {
Route::get('memberInfo/:name', 'user.UserHandle/getUserInfo');//会员个人资料页面获取信息
Route::get('TeamList', 'user.UserHandle/getTeamList');//获取团队信息
Route::get('TeamInfo/:name', 'user.UserHandle/getTeamInfo');//获取团队会员详细信息
Route::get('setContact/:name', 'user.UserHandle/setContact');//修改会员联系状态
Route::get('SystemList', 'user.UserHandle/getSystemList');//获取系统会员
Route::get('SystemInfo/:name', 'user.UserHandle/getSystemInfo');//获取系统会员详细信息
Route::get('getInstructorInfo', 'user.UserHandle/getInstructorInfo');//获取指导老师信息
Route::get('newestInfo', 'user.UserHandle/NewestInfo');//获取会员最新信息
Route::get('wechatUnbound', 'user.UserHandle/WechatUnbound');//解绑公众号
Route::post('setGroup/:name', 'user.UserHandle/setGroup');//修改团队会员等级
Route::post('setModifyPw/:name', 'user.UserHandle/setModifyPw');//修改团队会员密码
Route::post('upUserData', 'user.UserHandle/upUserInfo');//会员个人资料页面更新信息
Route::post('settglink', 'user.UserHandle/setTgLink');//修改推广识别码
Route::post('upvidwds', 'user.UserHandle/upWordVideoData');//小程序,会员提交视频和文字介绍
Route::post('lineRegUserInfo', 'user.UserHandle/lineRegUserInfo');//针对line注册的会员,进行一个资料完善
});

//订单相关  
Route::group('order/', function () {  
    Route::get('getlist', 'user.Order/getOrderList');//获取订单列表  
    Route::get('getData/:id', 'user.Order/getOrderId');//根据id获取订单信息  
    Route::get('confirm/:id', 'user.Order/confirmReceiptOrderId');//会员确认收货  
    Route::get('cancel/:id', 'user.Order/cancelOrderId');//会员取消订单  
    Route::get('softdel/:id', 'user.Order/deleteOrderId');//会员删除订单  
    // 评论相关  
    Route::get('getCommentPackage/:id', 'user.OrderComment/getOrderPackage');//会员获取评论订单  
    Route::post('upCommentContent/:id', 'user.OrderComment/commentOrderPackage');//会员提交评论订单内容  
    // 退款相关  
    Route::get('getReturnList', 'user.OrderReturn/getOrderReturnList');//获取退款列表  
    Route::get('getReturnId/:id', 'user.OrderReturn/getOrderReturnId');//根据id获取退换信息  
    Route::get('getReturnPackage/:id', 'user.OrderReturn/getOrderPackage');//退款页面获取订单的产品信息  
    Route::post('addReturnPackage', 'user.OrderReturn/addOrderReturn');//提交退款信息  
    Route::get('cancelService/:id', 'user.OrderReturn/cancelServiceList');//取消退换货  
});  

});

继续阅读 »

目前的路由是没有分组的,如果一个项目几百个页面,在pages.json文件全部展示出来,找起来是非常麻烦的,而且路由匹配的速度应该也不快,可以设计路由分组,同模块下多个页面,可以在一个组下,例如下面这种php的写法,也方便在编辑器折叠,找起来也比较方便
//会员数据请求
Route::group('user/', function(){
//会员信息查询与更新
Route::group('handle/', function () {
Route::get('memberInfo/:name', 'user.UserHandle/getUserInfo');//会员个人资料页面获取信息
Route::get('TeamList', 'user.UserHandle/getTeamList');//获取团队信息
Route::get('TeamInfo/:name', 'user.UserHandle/getTeamInfo');//获取团队会员详细信息
Route::get('setContact/:name', 'user.UserHandle/setContact');//修改会员联系状态
Route::get('SystemList', 'user.UserHandle/getSystemList');//获取系统会员
Route::get('SystemInfo/:name', 'user.UserHandle/getSystemInfo');//获取系统会员详细信息
Route::get('getInstructorInfo', 'user.UserHandle/getInstructorInfo');//获取指导老师信息
Route::get('newestInfo', 'user.UserHandle/NewestInfo');//获取会员最新信息
Route::get('wechatUnbound', 'user.UserHandle/WechatUnbound');//解绑公众号
Route::post('setGroup/:name', 'user.UserHandle/setGroup');//修改团队会员等级
Route::post('setModifyPw/:name', 'user.UserHandle/setModifyPw');//修改团队会员密码
Route::post('upUserData', 'user.UserHandle/upUserInfo');//会员个人资料页面更新信息
Route::post('settglink', 'user.UserHandle/setTgLink');//修改推广识别码
Route::post('upvidwds', 'user.UserHandle/upWordVideoData');//小程序,会员提交视频和文字介绍
Route::post('lineRegUserInfo', 'user.UserHandle/lineRegUserInfo');//针对line注册的会员,进行一个资料完善
});

//订单相关  
Route::group('order/', function () {  
    Route::get('getlist', 'user.Order/getOrderList');//获取订单列表  
    Route::get('getData/:id', 'user.Order/getOrderId');//根据id获取订单信息  
    Route::get('confirm/:id', 'user.Order/confirmReceiptOrderId');//会员确认收货  
    Route::get('cancel/:id', 'user.Order/cancelOrderId');//会员取消订单  
    Route::get('softdel/:id', 'user.Order/deleteOrderId');//会员删除订单  
    // 评论相关  
    Route::get('getCommentPackage/:id', 'user.OrderComment/getOrderPackage');//会员获取评论订单  
    Route::post('upCommentContent/:id', 'user.OrderComment/commentOrderPackage');//会员提交评论订单内容  
    // 退款相关  
    Route::get('getReturnList', 'user.OrderReturn/getOrderReturnList');//获取退款列表  
    Route::get('getReturnId/:id', 'user.OrderReturn/getOrderReturnId');//根据id获取退换信息  
    Route::get('getReturnPackage/:id', 'user.OrderReturn/getOrderPackage');//退款页面获取订单的产品信息  
    Route::post('addReturnPackage', 'user.OrderReturn/addOrderReturn');//提交退款信息  
    Route::get('cancelService/:id', 'user.OrderReturn/cancelServiceList');//取消退换货  
});  

});

收起阅读 »

html实体空格无效

js

空格分为 两种: 普通文本空格和html实体空格

普通文本空格 unicode 正则 描述
全角-中文空格键 \u3000 中文网页上常会出现

半角-英文空格键 \u0020 \s 最常见,写代码

html实体空格 unicode 十六进制 描述
  \u00a0 \xa0
1个字符宽度
不间断空格,主要用在office中,让一个单词在结尾处不会换行显示

  \u2002
1个字符宽度
半角空格

  \u2003
2个字符宽度
全角空格

\u2009 小于1个字符宽度
 

3.其他制表符
\n 回车(\u000a)
\t 水平制表符(\u0009)
\s 空格(\u0008)
\r 换行(\u000d)

解决方案1
将html空格替换成想要的unicode码

解决方案2 vue 的 v-html
<div v-html="'&nbsp;&nbsp;'"></div>

关于在线文档编辑时,文字对齐的有效操作:在全角的情况下点击空格键,对应的实体字符是&emsp;

继续阅读 »

空格分为 两种: 普通文本空格和html实体空格

普通文本空格 unicode 正则 描述
全角-中文空格键 \u3000 中文网页上常会出现

半角-英文空格键 \u0020 \s 最常见,写代码

html实体空格 unicode 十六进制 描述
&nbsp; \u00a0 \xa0
1个字符宽度
不间断空格,主要用在office中,让一个单词在结尾处不会换行显示

&ensp; \u2002
1个字符宽度
半角空格

&emsp; \u2003
2个字符宽度
全角空格

\u2009 小于1个字符宽度
&nbsp;

3.其他制表符
\n 回车(\u000a)
\t 水平制表符(\u0009)
\s 空格(\u0008)
\r 换行(\u000d)

解决方案1
将html空格替换成想要的unicode码

解决方案2 vue 的 v-html
<div v-html="'&nbsp;&nbsp;'"></div>

关于在线文档编辑时,文字对齐的有效操作:在全角的情况下点击空格键,对应的实体字符是&emsp;

收起阅读 »

网站变成APP与小程序就是那么容易(基于帝国7.5开发)

部分小白站长朋友们很想很想把自己的网站做成APP与各类小程序!感觉很高大上的感觉!(实测推广比网站难度大很多但是浏览速度比网站确实快很多,毕竟是渲染层与逻辑层是分开了的)其实是非常容易的!DZ与WORDPRESS插件市场已经有了就不重点说明了!自己去搜搜下吧!今天给大家带来一个好的插件!让帝国CMS也可以做成APP与各类小程序!(小编也是帝国的老粉丝)

经过一段时间学习uniapp发现是很简单的!只需要把帝国数据处理后的数据格式转换为json就可以了!安卓软件包!https://www.meiweny.cn/app/1.2.8.apk 微信小程序请微信搜索“美文苑”进行体验!!

前端所需要的模板文件与数据处理接口文件下载:https://www.meiweny.cn/ruanjianleyuan/32.html

继续阅读 »

部分小白站长朋友们很想很想把自己的网站做成APP与各类小程序!感觉很高大上的感觉!(实测推广比网站难度大很多但是浏览速度比网站确实快很多,毕竟是渲染层与逻辑层是分开了的)其实是非常容易的!DZ与WORDPRESS插件市场已经有了就不重点说明了!自己去搜搜下吧!今天给大家带来一个好的插件!让帝国CMS也可以做成APP与各类小程序!(小编也是帝国的老粉丝)

经过一段时间学习uniapp发现是很简单的!只需要把帝国数据处理后的数据格式转换为json就可以了!安卓软件包!https://www.meiweny.cn/app/1.2.8.apk 微信小程序请微信搜索“美文苑”进行体验!!

前端所需要的模板文件与数据处理接口文件下载:https://www.meiweny.cn/ruanjianleyuan/32.html

收起阅读 »

全新个人发卡网源码开源版内置免签支付接口可对接易支付

源码分享 源码

  在本文中,让我们看看如何实施支付网关PHP源代码项目。我们已经在一篇用PHP语言集成的文章中清楚地解释了这个过程。但是所有技术的步骤都是相同的。因此,请阅读此处的集成指南。其实步骤很简单,我们只需要输入商户密钥和salt。
  
  源码:paywks.top/ka
  
  这里我有使用框架,因为支付网关不像简单的过程。我们需要手动设置一些更改并实施代码。所以当我们使用COREPHP时,会面临更多的错误处理困难。这就是为什么大多数开发人员建议使用Laravel、Codeigniter等框架的原因。
  
  支付网关PHP要遵循的步骤
  
  如果您是该类别的初学者,请阅读官方文档。之后,您对构建代码有了一些想法。第一步是选择最好的支付网关提供商之一。
  
  我希望你的系统上已经有下载节点,以提取依赖管理器。所以首先通过命令提示符创建Laravel项目。
  
  useShipu\Aamarpay\Aamarpay;
  $config=[
  'store_id'=>'Yourstoreid',
  'signature_key'=>'Yoursignaturekey',
  'sandbox'=>true,
  'redirect_url'=>[
  'success'=>[
  'route'=>'payment.success'
  ],
  'cancel'=>[
  'route'=>'payment.cancel'
  ]
  ]
  ];
  $payment=newAamarpay($config);
  
  上面的代码解释了连接到数据库的模块的必填字段。然后只有我们能够与数据库系统进行通信。否则,确切的数据不会在后端通信中传输。
  
  
  use\Shipu\Aamarpay\Aamarpay;
  ...
  $payment=newAamarpay(config('aamarpay'));
  return$payment->customer([
  'cus_name'=>'ShipuAhamed',//Customername
  'cus_phone'=>'01616022669'//CustomerPhone
  'cus_email'=>'shipuahamed01@gmail.com',//Customeremail
  ])->transactionId()->amount(3500)->hiddenValue();
  or
  return$payment->customer([
  'cus_name'=>'ShipuAhamed',//Customername
  'cus_phone'=>'9854345483'//CustomerPhone
  'cus_email'=>'shipuahamed01@gmail.com',//Customeremail
  ])->amount(3500)->hiddenValue();
  
  Route::post('payment/success','YourMakePaymentsController@paymentSuccess')->name('payment.success');
  Route::post('payment/failed','YourMakePaymentsController@paymentFailed')->name('payment.failed');
  Route::post('payment/cancel','YourMakePaymentsController@paymentCancel')->name('payment.cancel');
  PHP库
  
  接下来,您需要在数据库中创建一个表来保存交易明细。接下来是在MySQL数据库中创建订单表的SQL。
  
  CREATETABLEorders(
  idint(11)NOTNULLAUTO_INCREMENT,
  namevarchar(100)COLLATEutf8_unicode_ciNOTNULL,
  emailvarchar(255)COLLATEutf8_unicode_ciNOTNULL,
  card_numbigint(20)NOTNULL,
  card_cvcint(5)NOTNULL,
  card_exp_monthvarchar(2)COLLATEutf8_unicode_ciNOTNULL,
  card_exp_yearvarchar(5)COLLATEutf8_unicode_ciNOTNULL,
  item_namevarchar(255)COLLATEutf8_unicode_ciNOTNULL,
  item_numbervarchar(50)COLLATEutf8_unicode_ciNOTNULL,
  item_pricefloat(10,2)NOTNULL,
  item_price_currencyvarchar(10)COLLATEutf8_unicode_ciNOTNULLDEFAULT'usd',
  paid_amountvarchar(10)COLLATEutf8_unicode_ciNOTNULL,
  paid_amount_currencyvarchar(10)COLLATEutf8_unicode_ciNOTNULL,
  txn_idvarchar(100)COLLATEutf8_unicode_ciNOTNULL,
  payment_statusvarchar(50)COLLATEutf8_unicode_ciNOTNULL,
  createddatetimeNOTNULL,
  modifieddatetimeNOTNULL,
  PRIMARYKEY(id)
  )ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_unicode_ci;
  
  数据库配置(dbConfig.php)
  
  您将需要dbConfig.php文件来连接和选择数据库。在数据库凭证后指定数据库主机($dbHost)、用户名($dbUsername)、密码($dbPassword)和名称($dbName)。
  接下来,我们将使用StripePHP库来处理卡支付。该图书馆可在此处获得。
  
  //checkwhetherstripetokenisnotempty
  if(!empty($_POST['stripeToken'])){
  //gettoken,cardanduserinfofromtheform
  $token=$_POST['stripeToken'];
  $name=$_POST['name'];
  $email=$_POST['email'];
  $card_num=$_POST['card_num'];
  $card_cvc=$_POST['cvc'];
  $card_exp_month=$_POST['exp_month'];
  $card_exp_year=$_POST['exp_year'];
  //includeStripePHPlibrary
  require_once('stripe-php/init.php');
  //setapikey
  $stripe=array(
  "secret_key"=>"Your_API_Secret_Key",
  "publishable_key"=>"Your_API_Publishable_Key"
  );
  \Stripe\Stripe::setApiKey($stripe['secret_key']);
  //addcustomertostripe
  $customer=\Stripe\Customer::create(array(
  'email'=>$email,
  'source'=>$token
  ));
  //iteminformation
  $itemName="PremiumScriptCodexWorld";
  $itemNumber="PS123456";
  $itemPrice=55;
  $currency="usd";
  $orderID="SKA92712382139";
  //chargeacreditoradebitcard
  $charge=\Stripe\Charge::create(array(
  'customer'=>$customer->id,
  'amount'=>$itemPrice,
  'currency'=>$currency,
  'description'=>$itemName,
  'metadata'=>array(
  'order_id'=>$orderID
  )
  ));
  //retrievechargedetails
  $chargeJson=$charge->jsonSerialize();
  //checkwhetherthechargeissuccessful
  if($chargeJson['amount_refunded']==0&&empty($chargeJson
  ['failure_code'])&&$chargeJson['paid']==1&&$chargeJson['captured']==1){
  //orderdetails
  $amount=$chargeJson['amount'];
  $balance_transaction=$chargeJson['balance_transaction'];
  $currency=$chargeJson['currency'];
  $status=$chargeJson['status'];
  $date=date("Y-m-dH:i:s");
  //includedatabaseconfigfile
  include_once'dbConfig.php';
  //inserttansactiondataintothedatabase
  $sql=
  "INSERTINTOorders(name,email,card_num,card_cvc,card_exp_month,card_exp_year,
  item_name,item_number,item_price,item_price_currency,paid_amount,
  paid_amount_currency,txn_id,payment_status,created,modified)VALUES
  ('".$name."','".$email."','".$card_num."','".$card_cvc."','".$card_exp_month."',
  '".$card_exp_year."','".$itemName."','".$itemNumber."','".$itemPrice."','".$currency."',
  '".$amount."','".$currency."','".$balance_transaction."'
  ,'".$status."','".$date."','".$date."')";
  $insert=$db->query($sql);
  $last_insert_id=$db->insert_id;
  //iforderinsertedsuccessfully
  if($last_insert_id&&$status=='succeeded'){
  $statusMsg="<h2>Thetransactionwassuccessful.</h2>
  <h4>OrderID:{$last_insert_id}</h4>";
  }else{
  $statusMsg="Transactionhasbeenfailed";
  }
  }else{
  $statusMsg="Transactionhasbeenfailed";
  }
  }else{
  $statusMsg="Formsubmissionerror.......";
  }
  //showsuccessorerrormessage
  echo$statusMsg;

继续阅读 »

  在本文中,让我们看看如何实施支付网关PHP源代码项目。我们已经在一篇用PHP语言集成的文章中清楚地解释了这个过程。但是所有技术的步骤都是相同的。因此,请阅读此处的集成指南。其实步骤很简单,我们只需要输入商户密钥和salt。
  
  源码:paywks.top/ka
  
  这里我有使用框架,因为支付网关不像简单的过程。我们需要手动设置一些更改并实施代码。所以当我们使用COREPHP时,会面临更多的错误处理困难。这就是为什么大多数开发人员建议使用Laravel、Codeigniter等框架的原因。
  
  支付网关PHP要遵循的步骤
  
  如果您是该类别的初学者,请阅读官方文档。之后,您对构建代码有了一些想法。第一步是选择最好的支付网关提供商之一。
  
  我希望你的系统上已经有下载节点,以提取依赖管理器。所以首先通过命令提示符创建Laravel项目。
  
  useShipu\Aamarpay\Aamarpay;
  $config=[
  'store_id'=>'Yourstoreid',
  'signature_key'=>'Yoursignaturekey',
  'sandbox'=>true,
  'redirect_url'=>[
  'success'=>[
  'route'=>'payment.success'
  ],
  'cancel'=>[
  'route'=>'payment.cancel'
  ]
  ]
  ];
  $payment=newAamarpay($config);
  
  上面的代码解释了连接到数据库的模块的必填字段。然后只有我们能够与数据库系统进行通信。否则,确切的数据不会在后端通信中传输。
  
  
  use\Shipu\Aamarpay\Aamarpay;
  ...
  $payment=newAamarpay(config('aamarpay'));
  return$payment->customer([
  'cus_name'=>'ShipuAhamed',//Customername
  'cus_phone'=>'01616022669'//CustomerPhone
  'cus_email'=>'shipuahamed01@gmail.com',//Customeremail
  ])->transactionId()->amount(3500)->hiddenValue();
  or
  return$payment->customer([
  'cus_name'=>'ShipuAhamed',//Customername
  'cus_phone'=>'9854345483'//CustomerPhone
  'cus_email'=>'shipuahamed01@gmail.com',//Customeremail
  ])->amount(3500)->hiddenValue();
  
  Route::post('payment/success','YourMakePaymentsController@paymentSuccess')->name('payment.success');
  Route::post('payment/failed','YourMakePaymentsController@paymentFailed')->name('payment.failed');
  Route::post('payment/cancel','YourMakePaymentsController@paymentCancel')->name('payment.cancel');
  PHP库
  
  接下来,您需要在数据库中创建一个表来保存交易明细。接下来是在MySQL数据库中创建订单表的SQL。
  
  CREATETABLEorders(
  idint(11)NOTNULLAUTO_INCREMENT,
  namevarchar(100)COLLATEutf8_unicode_ciNOTNULL,
  emailvarchar(255)COLLATEutf8_unicode_ciNOTNULL,
  card_numbigint(20)NOTNULL,
  card_cvcint(5)NOTNULL,
  card_exp_monthvarchar(2)COLLATEutf8_unicode_ciNOTNULL,
  card_exp_yearvarchar(5)COLLATEutf8_unicode_ciNOTNULL,
  item_namevarchar(255)COLLATEutf8_unicode_ciNOTNULL,
  item_numbervarchar(50)COLLATEutf8_unicode_ciNOTNULL,
  item_pricefloat(10,2)NOTNULL,
  item_price_currencyvarchar(10)COLLATEutf8_unicode_ciNOTNULLDEFAULT'usd',
  paid_amountvarchar(10)COLLATEutf8_unicode_ciNOTNULL,
  paid_amount_currencyvarchar(10)COLLATEutf8_unicode_ciNOTNULL,
  txn_idvarchar(100)COLLATEutf8_unicode_ciNOTNULL,
  payment_statusvarchar(50)COLLATEutf8_unicode_ciNOTNULL,
  createddatetimeNOTNULL,
  modifieddatetimeNOTNULL,
  PRIMARYKEY(id)
  )ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_unicode_ci;
  
  数据库配置(dbConfig.php)
  
  您将需要dbConfig.php文件来连接和选择数据库。在数据库凭证后指定数据库主机($dbHost)、用户名($dbUsername)、密码($dbPassword)和名称($dbName)。
  接下来,我们将使用StripePHP库来处理卡支付。该图书馆可在此处获得。
  
  //checkwhetherstripetokenisnotempty
  if(!empty($_POST['stripeToken'])){
  //gettoken,cardanduserinfofromtheform
  $token=$_POST['stripeToken'];
  $name=$_POST['name'];
  $email=$_POST['email'];
  $card_num=$_POST['card_num'];
  $card_cvc=$_POST['cvc'];
  $card_exp_month=$_POST['exp_month'];
  $card_exp_year=$_POST['exp_year'];
  //includeStripePHPlibrary
  require_once('stripe-php/init.php');
  //setapikey
  $stripe=array(
  "secret_key"=>"Your_API_Secret_Key",
  "publishable_key"=>"Your_API_Publishable_Key"
  );
  \Stripe\Stripe::setApiKey($stripe['secret_key']);
  //addcustomertostripe
  $customer=\Stripe\Customer::create(array(
  'email'=>$email,
  'source'=>$token
  ));
  //iteminformation
  $itemName="PremiumScriptCodexWorld";
  $itemNumber="PS123456";
  $itemPrice=55;
  $currency="usd";
  $orderID="SKA92712382139";
  //chargeacreditoradebitcard
  $charge=\Stripe\Charge::create(array(
  'customer'=>$customer->id,
  'amount'=>$itemPrice,
  'currency'=>$currency,
  'description'=>$itemName,
  'metadata'=>array(
  'order_id'=>$orderID
  )
  ));
  //retrievechargedetails
  $chargeJson=$charge->jsonSerialize();
  //checkwhetherthechargeissuccessful
  if($chargeJson['amount_refunded']==0&&empty($chargeJson
  ['failure_code'])&&$chargeJson['paid']==1&&$chargeJson['captured']==1){
  //orderdetails
  $amount=$chargeJson['amount'];
  $balance_transaction=$chargeJson['balance_transaction'];
  $currency=$chargeJson['currency'];
  $status=$chargeJson['status'];
  $date=date("Y-m-dH:i:s");
  //includedatabaseconfigfile
  include_once'dbConfig.php';
  //inserttansactiondataintothedatabase
  $sql=
  "INSERTINTOorders(name,email,card_num,card_cvc,card_exp_month,card_exp_year,
  item_name,item_number,item_price,item_price_currency,paid_amount,
  paid_amount_currency,txn_id,payment_status,created,modified)VALUES
  ('".$name."','".$email."','".$card_num."','".$card_cvc."','".$card_exp_month."',
  '".$card_exp_year."','".$itemName."','".$itemNumber."','".$itemPrice."','".$currency."',
  '".$amount."','".$currency."','".$balance_transaction."'
  ,'".$status."','".$date."','".$date."')";
  $insert=$db->query($sql);
  $last_insert_id=$db->insert_id;
  //iforderinsertedsuccessfully
  if($last_insert_id&&$status=='succeeded'){
  $statusMsg="<h2>Thetransactionwassuccessful.</h2>
  <h4>OrderID:{$last_insert_id}</h4>";
  }else{
  $statusMsg="Transactionhasbeenfailed";
  }
  }else{
  $statusMsg="Transactionhasbeenfailed";
  }
  }else{
  $statusMsg="Formsubmissionerror.......";
  }
  //showsuccessorerrormessage
  echo$statusMsg;

收起阅读 »

iOS AppStore上架流程图文详解2021版 (上)

iOS打包 Apple云端打包

到了2021年,虽然网上也有大牛写过很多IOS App上架流程资料,但随着苹果发布机制的微调有些已经过时了。我就趁着这次刚刚发布成功的鲜活经验,记录下来,做一下补充。
1、首先得注册Apple Developer的开发者账号,最后如果要上架苹果商店,这个账号是要交年费的,核算下来大概600多元人民币。
2、接下来要登录Apple Developer网站,点击“Account”栏目
3、如果该App需要多人协作开发,请进入People进入人员编辑。注意负责上架AppStore的人员需要有管理级别的权限。
4、人员设置完成过后,进入“Certificates...”页面了。
1先申请证书
2如果还在开发App,就需要申请下Apple Development证书,里面可以申请开发人员的AppleID以及测试真机
如果App额外的敏感功能,比如大部分App都需要的推送,则要申请Apple Push Notifucation service SSL(Sandbox & Production)
如果需要发布,则要申请iOS Distribution(App Store and Ad Hoc),然后点击下一步"Continue"
这里就需要上传CSR文件了,CSR是Certificate Signing Request的英文缩写,即证书请求文件。我们需要在电脑上《钥匙串访问》中生成。
点击钥匙串访问-->证书助理-->从证书颁发机构请求证书...
进入CSR生成界面,选择"保存到磁盘",在Create a New Certificate页面选择改文件,继续下一步,然后点击存储,双击下载后的证书就能完成配置。
3添加Identifiers,然后选择App IDs 接着下一步,
选择App接着下一步,这边要填写App的描述和Bundle ID,
如果有需要权限的功能也要在这边勾选,比如"Push Notifications"
4接着申请Profiles
如果还在开发阶段,可以选择iOS App Development。
如果要发布就选择App Store,接着选择你要发布的App ID,然后选择你之前申请的Certificates证书。
在Xcode App项目Release Signing签名中选择刚才生成的Profiles
APP Uploader APP开发助手-iOS APP上架到App Store的辅助工具,解决iOS APP上架繁琐费时的情况,帮助跨平台APP开发者上架苹果应用,在没有配置Mac苹果机的情况,实现iOS证书申请,创建iOS开发者证书、iOS发布证书等各类证书,iOS开发者在Windows、Linux或Mac系统中上传IPA到App Store,简化iOS APP上架流程!在Windows pc中轻松快速上架你的APP。
Appuploader是一个非常好用的IPA上传发布工具,使用它可以辅助iOS软件的开发,可以很便捷的将app上传到AppStore,并且自带各种证书的申请,对于个人开发者来说很实用。只需输入证书名称,创建邮箱等信息即可创建证书,并且创建的证书,不绑定电脑。
App 开发助手可以直接在windows,linux或mac,不需要Mac,不需要钥匙串助手,只需输入证书的名称,邮箱和密码就可以创建,简单快速,并且申请的iOS证书可以不同电脑使用,证书协同无障碍,团队开发管理更高效。

继续阅读 »

到了2021年,虽然网上也有大牛写过很多IOS App上架流程资料,但随着苹果发布机制的微调有些已经过时了。我就趁着这次刚刚发布成功的鲜活经验,记录下来,做一下补充。
1、首先得注册Apple Developer的开发者账号,最后如果要上架苹果商店,这个账号是要交年费的,核算下来大概600多元人民币。
2、接下来要登录Apple Developer网站,点击“Account”栏目
3、如果该App需要多人协作开发,请进入People进入人员编辑。注意负责上架AppStore的人员需要有管理级别的权限。
4、人员设置完成过后,进入“Certificates...”页面了。
1先申请证书
2如果还在开发App,就需要申请下Apple Development证书,里面可以申请开发人员的AppleID以及测试真机
如果App额外的敏感功能,比如大部分App都需要的推送,则要申请Apple Push Notifucation service SSL(Sandbox & Production)
如果需要发布,则要申请iOS Distribution(App Store and Ad Hoc),然后点击下一步"Continue"
这里就需要上传CSR文件了,CSR是Certificate Signing Request的英文缩写,即证书请求文件。我们需要在电脑上《钥匙串访问》中生成。
点击钥匙串访问-->证书助理-->从证书颁发机构请求证书...
进入CSR生成界面,选择"保存到磁盘",在Create a New Certificate页面选择改文件,继续下一步,然后点击存储,双击下载后的证书就能完成配置。
3添加Identifiers,然后选择App IDs 接着下一步,
选择App接着下一步,这边要填写App的描述和Bundle ID,
如果有需要权限的功能也要在这边勾选,比如"Push Notifications"
4接着申请Profiles
如果还在开发阶段,可以选择iOS App Development。
如果要发布就选择App Store,接着选择你要发布的App ID,然后选择你之前申请的Certificates证书。
在Xcode App项目Release Signing签名中选择刚才生成的Profiles
APP Uploader APP开发助手-iOS APP上架到App Store的辅助工具,解决iOS APP上架繁琐费时的情况,帮助跨平台APP开发者上架苹果应用,在没有配置Mac苹果机的情况,实现iOS证书申请,创建iOS开发者证书、iOS发布证书等各类证书,iOS开发者在Windows、Linux或Mac系统中上传IPA到App Store,简化iOS APP上架流程!在Windows pc中轻松快速上架你的APP。
Appuploader是一个非常好用的IPA上传发布工具,使用它可以辅助iOS软件的开发,可以很便捷的将app上传到AppStore,并且自带各种证书的申请,对于个人开发者来说很实用。只需输入证书名称,创建邮箱等信息即可创建证书,并且创建的证书,不绑定电脑。
App 开发助手可以直接在windows,linux或mac,不需要Mac,不需要钥匙串助手,只需输入证书的名称,邮箱和密码就可以创建,简单快速,并且申请的iOS证书可以不同电脑使用,证书协同无障碍,团队开发管理更高效。

收起阅读 »

一步一腳印的 iOS App 上架和更新流程

iOS打包 Apple证书

APP Uploader APP开发助手-iOS APP上架到App Store的辅助工具,解决iOS APP上架繁琐费时的情况,帮助跨平台APP开发者上架苹果应用,在没有配置Mac苹果机的情况,实现iOS证书申请,创建iOS开发者证书、iOS发布证书等各类证书,iOS开发者在Windows、Linux或Mac系统中上传IPA到App Store,简化iOS APP上架流程!在Windows pc中轻松快速上架你的APP。
Appuploader是一个非常好用的IPA上传发布工具,使用它可以辅助iOS软件的开发,可以很便捷的将app上传到AppStore,并且自带各种证书的申请,对于个人开发者来说很实用。只需输入证书名称,创建邮箱等信息即可创建证书,并且创建的证书,不绑定电脑。
App 开发助手可以直接在windows,linux或mac,不需要Mac,不需要钥匙串助手,只需输入证书的名称,邮箱和密码就可以创建,简单快速,并且申请的iOS证书可以不同电脑使用,证书协同无障碍,团队开发管理更高效。
来APICloud移动应用开发平台学习更多APP开app上架应用市场需要什么条件
App Store作为苹果官方的应用商店,审核严格周期长一直让用户头疼不已,很多app都“死”在了审核这一关,那我们就要放弃iOS用户了吗?当然不是!本期我们从iOS app上架流程开始梳理,详细了解下iOS app上架的那些事。
iOS app上架总体流程:
1登录苹果开发者中心,注册开发者账号
如果你是第一次申请注册使用Apple ID登录苹果开发者网站,需要同意“苹果开发者协议”,提交请求,这个时候你的Apple ID 就已经成为了一个开发者的ID了。如图1-1:
苹果开发者中心网址:​​https://developer.apple.com/​​
同意苹果开发者协议并提交申请
2申请付费开发者,加入苹果开发计划
加入苹果开发者计划
开始注册
注册说明
补充说明:
双重验证相关
苹果新规定Apple ID需开启双重验证才能注册开发者账号,所以在加入开发者之前需要根据提示开启设备进行双重验证;验证方法采用登录电脑上的iCloud根据提示进行验证(或者其他设备,如登录手机进行双重验证),以下是部分相关图片
双重验证相关
双重验证相关
选择开发者类型
补充说明:
Apple 开发者账号

  1. 个人账号:个人申请用于开发 Apple App 所使用的账号,仅限于个人使用,可以在 App Store 发布应用,申请比较容易,¥688.00/年 ($99.00/year)。
  2. 公司账号:以公司名义申请的开发者账号,用于公司内部的开发者共用,可以在 App Store 发布应用,申请流程相对麻烦,¥688.00/年 ($99.00/year)。
  3. 企业账号:一般是公司规模在 500 人以上的企业,用于内部测试、分发应用的账号,不能在 App Store 发布应用,申请流程相对麻烦,¥1988/($299.00/year)。
    · 不同开发者账号步骤与所需资料
    填写详细的注册信息,统一相关协议,通过验证审核之后再次点击继续进入支付页面,具体步骤参考图2-7:
    填写注册信息
    同意协议并且继续
    注册等待验证通过
    支付
    再次登录
    填写付费信息的页面
    支付成功后,苹果会在48小时内对订单进行处理,之后可能会收到邮件要求到指定的页面上传身份证照片。
    如果遇到任何问题,可以拨打苹果开发的售后服务电话4006701855。
    补充说明:
    ·邓白氏DUNS的申请
    邓白氏DUNS编码相当于公司在苹果公认的权威组织中注册了自己的身份证;可以点击相关链接先进行验证,没有可以直接申请。具体申请步骤可以参考百度经验:​​https://jingyan.baidu.com/article/27fa7326bd29df46f9271f10.html​​
    3创建证书
    使用APICloud平台开发iOS应用需要用到几个证书,下面的图为各个证书使用的地方。接下来为各个证书的创建教程。
    4创建App ID
    首先打开苹果开发网站,通过Account进入开发账户,如图:
    登录成功后选择Certificates, Identifiers
继续阅读 »

APP Uploader APP开发助手-iOS APP上架到App Store的辅助工具,解决iOS APP上架繁琐费时的情况,帮助跨平台APP开发者上架苹果应用,在没有配置Mac苹果机的情况,实现iOS证书申请,创建iOS开发者证书、iOS发布证书等各类证书,iOS开发者在Windows、Linux或Mac系统中上传IPA到App Store,简化iOS APP上架流程!在Windows pc中轻松快速上架你的APP。
Appuploader是一个非常好用的IPA上传发布工具,使用它可以辅助iOS软件的开发,可以很便捷的将app上传到AppStore,并且自带各种证书的申请,对于个人开发者来说很实用。只需输入证书名称,创建邮箱等信息即可创建证书,并且创建的证书,不绑定电脑。
App 开发助手可以直接在windows,linux或mac,不需要Mac,不需要钥匙串助手,只需输入证书的名称,邮箱和密码就可以创建,简单快速,并且申请的iOS证书可以不同电脑使用,证书协同无障碍,团队开发管理更高效。
来APICloud移动应用开发平台学习更多APP开app上架应用市场需要什么条件
App Store作为苹果官方的应用商店,审核严格周期长一直让用户头疼不已,很多app都“死”在了审核这一关,那我们就要放弃iOS用户了吗?当然不是!本期我们从iOS app上架流程开始梳理,详细了解下iOS app上架的那些事。
iOS app上架总体流程:
1登录苹果开发者中心,注册开发者账号
如果你是第一次申请注册使用Apple ID登录苹果开发者网站,需要同意“苹果开发者协议”,提交请求,这个时候你的Apple ID 就已经成为了一个开发者的ID了。如图1-1:
苹果开发者中心网址:​​https://developer.apple.com/​​
同意苹果开发者协议并提交申请
2申请付费开发者,加入苹果开发计划
加入苹果开发者计划
开始注册
注册说明
补充说明:
双重验证相关
苹果新规定Apple ID需开启双重验证才能注册开发者账号,所以在加入开发者之前需要根据提示开启设备进行双重验证;验证方法采用登录电脑上的iCloud根据提示进行验证(或者其他设备,如登录手机进行双重验证),以下是部分相关图片
双重验证相关
双重验证相关
选择开发者类型
补充说明:
Apple 开发者账号

  1. 个人账号:个人申请用于开发 Apple App 所使用的账号,仅限于个人使用,可以在 App Store 发布应用,申请比较容易,¥688.00/年 ($99.00/year)。
  2. 公司账号:以公司名义申请的开发者账号,用于公司内部的开发者共用,可以在 App Store 发布应用,申请流程相对麻烦,¥688.00/年 ($99.00/year)。
  3. 企业账号:一般是公司规模在 500 人以上的企业,用于内部测试、分发应用的账号,不能在 App Store 发布应用,申请流程相对麻烦,¥1988/($299.00/year)。
    · 不同开发者账号步骤与所需资料
    填写详细的注册信息,统一相关协议,通过验证审核之后再次点击继续进入支付页面,具体步骤参考图2-7:
    填写注册信息
    同意协议并且继续
    注册等待验证通过
    支付
    再次登录
    填写付费信息的页面
    支付成功后,苹果会在48小时内对订单进行处理,之后可能会收到邮件要求到指定的页面上传身份证照片。
    如果遇到任何问题,可以拨打苹果开发的售后服务电话4006701855。
    补充说明:
    ·邓白氏DUNS的申请
    邓白氏DUNS编码相当于公司在苹果公认的权威组织中注册了自己的身份证;可以点击相关链接先进行验证,没有可以直接申请。具体申请步骤可以参考百度经验:​​https://jingyan.baidu.com/article/27fa7326bd29df46f9271f10.html​​
    3创建证书
    使用APICloud平台开发iOS应用需要用到几个证书,下面的图为各个证书使用的地方。接下来为各个证书的创建教程。
    4创建App ID
    首先打开苹果开发网站,通过Account进入开发账户,如图:
    登录成功后选择Certificates, Identifiers
收起阅读 »