предисловие
Апплет уже начал играть во время внутреннего теста, но в начале, я чувствовал, что sx вещи настолько стерты, сетевой запрос не возвращает Promise, а использует Callback, и значение не может быть записано при передаче значения. наборы данных могут использоваться в методе, а компонентизация не поддерживается в этой комплексной компонентной среде...
На самом деле, в начале это было в основном дело привычки при написании.Придерживаясь того, что я не занимаюсь мелкой разработкой программ, я потерплю ваше отношение и отпущу. Однако есть непредвиденные обстоятельства.В последнее время в связи с нуждами бизнеса приходится заниматься разработкой небольших программ.Я не выношу свой упрямый характер. Решительно изменил неприятные места, чтобы иметь возможность ходить так, как мне нравится, и наткнулся на другие ямы, медленно заполнил их одну за другой, записал их и организовал в статьи.
сетевой запрос
Апплет веб-запроса предоставляетwx.request, это то, на что я хочу пожаловаться больше всего, присмотритесь к API, не является ли этот продукт n-летней давности$.ajax
Да, такой старый.
// 官方例子
wx.request({
url: 'test.php', //仅为示例,并非真实的接口地址
data: {
x: '' ,
y: ''
},
header: {
'content-type': 'application/json' // 默认值
},
success: function(res) {
console.log(res.data)
}
})
Сейчас всего один запрос, и такое чувство, что долго писать. А что если странице нужно несколько запросов? А если порядок запросов все-таки требуется? Всякие вложенности вонючие и длинные. После этого интерфейс отображается снова, и он мгновенно ошеломлен.
В этот раз я слабо присмотрелся к поддержке JS-версии апплета Oye, который более добросовестно поддерживает ES6. То есть вполне возможно, что мы можем изменить его на Promise. Посмотрим, как я переделаю.
/* utils/api.js 自定义网络请求 */
const baseURL = 'https://yourapi.com' // 自己后台API地址
const http = ({ url = '', params = {}, ...other} = {}) => {
wx.showLoading({
title: '加载中...'
})
let time = Date.now()
console.log(`开始:${time}`)
return new Promise((resolve, reject) => {
wx.request({
url: getUrl(url),
data: params,
header: getHeader(),
...other,
complete: (res) => {
wx.hideLoading()
console.log(`耗时:${Date.now() - time}`)
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data)
} else {
reject(res)
}
}
})
})
}
const getUrl = url => {
if (url.indexOf('://') == -1) {
url = baseURL + url
}
return url
}
const getHeader = () => {
try {
var token = wx.getStorageSync('token')
if (token) {
return { 'token': token }
}
return {}
} catch (e) {
return {}
}
}
module.exports = {
baseURL,
get (url, params = {}) {
return http({
url,
params
})
},
post(url, params = {}) {
return http({
url,
params,
method: 'post'
})
},
put(url, params = {}) {
return http({
url,
params,
method: 'put'
})
},
// 这里不能使用 delete, delete为关键字段
myDelete(url, params = {}) {
return http({
url,
params,
method: 'delete'
})
}
}
После этого мы можем использовать его как обычно.Давайте напишем простой пример.
const api = require('../../utils/api.js')
// 单个请求
api.get('list').then(res => {
console.log(res)
}).catch(e => {
console.log(e)
})
// 一个页面多个请求
Promise.all([
api.get('list'),
api.get(`detail/${id}`)
]).then(result => {
console.log(result)
}).catch(e => {
console.log(e)
})
Друзья, привыкшие к fetch и axios, должны предпочесть этот способ написания. Так же столкнулся с проблемой при совершении сетевых запросов, проблема авторизации входа.
проблема со входом
При подаче заявки нельзя избежать операции входа в систему. Личная информация пользователя, соответствующие списки избранного и другие функции должны быть зарегистрированы, прежде чем пользователь сможет работать. Как правило, мы используем токен в качестве идентификации. Тогда это будет связано с такими проблемами, как токен не существует, пользователь входит в систему в первый раз, срок действия токена истекает, а затем снова входит в систему. Более распространенной операцией является переход непосредственно на страницу входа.
Затем появляется яма, у апплета нет интерфейса входа, он используетwx.login
.wx.login
Получите код, код для сдерживания нашего запроса будет последним, чтобы вернуть небольшой токен в программу здесь, сохраните это значениеtoken
Приносите это значение с каждым запросом. (Подробности можно посмотретьВход в мини-программу. )
Но достаточно ли этого? Очевидно нет. Как правило, также необходимо предоставить информацию о пользователе, такую как псевдоним пользователя WeChat, аватар WeChat и т. д., в настоящее время необходимо использоватьwx.getUserInfo
, Это связано с проблемой авторизации пользователя, оставить яму, а затем решить ее позже. Достаточно ли принести информацию о пользователе? слишком молод слишком просто! В нашем проекте не может быть только небольших программ, на соответствующей общедоступной платформе WeChat могут быть соответствующие приложения, нам нужно открыть систему учетных записей, чтобы у пользователей была одна и та же учетная запись в нашем проекте. Это нужно использоватьОткрытая платформа WeChatкоторый предоставилUnionID
.
ps. Исходя из простоты распространения мини-программ в WeChat, обычно предоставляется механизм приглашения и вознаграждения, чтобы поощрять пользователей к распространению и обмену. Однако в WeChat индуцированный обмен будет осуществляться гармонично. Используйте с осторожностью. (Эта статья добавит эту функцию в пример)
Увидев это, вы чувствуете, что ваша голова слишком велика, и так много ям для маленькой функции входа в систему. Когда я был молод, я дрожал~~~. Начните заполнять медленно. Сначала код входа
/* utils/api.js 自定义网络请求 */
...
function login() {
return new Promise((resolve, reject) => {
// 先调用 wx.login 获取到 code
wx.login({
success: res => {
// 再调用 wx.getUserInfo 获取到用户的一些信息 (一些基本信息,以及生成UnionID 所用到的信息 比如 rawData, signature, encryptedData, iv)
wx.getUserInfo({
// 若获取不到用户信息 (最大可能是用户授权不允许,也有可能是网络请求失败,但该情况很少)
fail: (e) => {
reject(e)
},
success: ({ rawData, signature, encryptedData, iv }) => {
let param = {
code: res.code,
rawData,
signature,
encryptedData,
iv
}
// 若有邀请ID
try {
let invite = wx.getStorageSync('invite')
if (invite) {
param.invite = invite
}
} catch (e) {
}
// 登录操作
http({
url: 'login',
params: param,
method: 'post'
}).then(res => {
// 该为我们后端的逻辑 若code > 0为登录成功,其他情况皆为异常 (视自身情况而定)
if (res.code > 0) {
// 保存用户信息
wx.setStorage({
key: 'userinfo',
data: res.data
})
wx.setStorage({
key: "token",
data: res.message,
success: () => {
resolve(res)
}
})
} else {
reject(res)
}
}).catch(error => reject(error))
}
})
}
})
})
}
...
Проблема с авторизацией
По приведенному выше коду ясно видно, что если пользователь не разрешает апплету получать информацию о своем пользователе при входе в систему, он может продолжить работу. Что произойдет, если пользователь нажмет «Отклонить» в это время?
Оно пустое!~~ Какого хрена! Мусорный сломанный апплет~~ спокойные пользователи тоже будут сбиты с толку. кто я? Что я должен делать?
Может быть вы подумаете, что пользователь просто нажимает разрешение, как же так можно быть таким глупым, таких пользователей точно не много и так далее. Я добавил в наш апплет статистику о20%
пользователей нажали «Отклонить», и если мы не предпримем никаких дальнейших действий, эти 20% пользователей будут потеряны навсегда. Мы никак не можем принять это последствие.
После нашего группового исследования и обсуждения мы придумали ряд решений.
Конкретный код может быть выражен следующим образом, используемыйwx.openSetting
для перехода к настройке интерфейса авторизации.
/* index.js */
// 若有用户信息存在则继续
Page({
onLoad () {
wx.getStorage({
key: 'userinfo',
success: (res) => {
this.setUserinfo(res)
},
fail: (res) => {
api.login().then((res) => {
this.setUserinfo(res)
}).catch(e => {
if (e.errMsg && e.errMsg === 'getUserInfo:fail auth deny') {
this.setData({
isauth: false
})
}
})
}
})
},
toSetting() {
wx.openSetting({
success: (res) => {
this.setData({
isauth: res.authSetting['scope.userInfo']
})
if (res.authSetting['scope.userInfo']) {
api.login().then((res) => {
this.setUserinfo(res)
})
}
}
})
}
})
// setUserinfo 就是对用户信息做一下处理 不具体展开了
/* index.wxml */
<view class="unauth" wx:if="{{!isauth}}">
<image class="unauth-img" src="../../images/auth.png"></image>
<text class="unauth-text">检查到您没打开授权</text>
<button class="color-button unauth-button" bindtap="toSetting">去设置</button>
</view>
<view class="container" wx:else>
...
</view>
проблема с аннулированием токена
Токен, полученный при входе в систему, ограничен по времени. Что произойдет, если он истечет? Если бэкенд-партнер спроектирует API интерфейса строго в соответствии со спецификацией REST API, он вернет нам неверный http-код 401. (Смысл общих Http-кодов и связанных с ними кодов не будет раскрываться в этой статье, а те, кто не понимает, могут сами погуглить Baidu.) После 401 нам нужно соответствующим образом поступить с кодом. можно записать следующим образом
api.get('list').then(res => {
/* do something */
}).catch(e => {
if (res.statusCode === 401) {
api.login().then(() => {
api.get('list').then(res => {
/* do something */
})
})
}
})
Вроде бы проблем нет, и требования выполнены. Но вы обнаружите, что есть большая проблема.
- К каждому запросу нужно добавлять оценку 401. Количество кода в этом блоке очень пугает, когда проект большой.
- Обработка после возврата интерфейса
/* do something */
Повторяется (конечно, это все содержимое извлекается, также звонки на линии здесь, но все же хотят позвонить здесь также опущены ^ - ^)
Повторяем, чего мы хотим добиться.
- Решение 401 необходимо добавлять после каждого запроса
- Повторно войдите в систему, если вы не авторизованы
- Продолжить предыдущий запрос после повторного входа в систему
- Возврат результата запроса к результату первого запроса (для достижения неперцептивного повторного входа в систему для получения информации)
Это отражает преимущества самостоятельной инкапсуляции сетевого запроса.Мы можем напрямую переписать обработку ошибок в методе http в api.js. Над кодом:
const http = ({ url = '', params = {}, ...other} = {}) => {
wx.showLoading({
title: '加载中...'
})
let time = Date.now()
console.log(`开始:${time}`)
return new Promise((resolve, reject) => {
wx.request({
url: getUrl(url),
data: params,
header: getHeader(),
...other,
complete: (res) => {
wx.hideLoading()
console.log(`耗时:${Date.now() - time}`)
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data)
} else if (res.statusCode === 401) {
// 401 为鉴权失败 很大可能是token过期
// 重新登录 并且重复请求
login().then(res => {
http({ url, params, ...other }).then(res => {
resolve(res)
})
})
} else {
reject(res)
}
}
})
})
}
резюме
Сетевой запрос является неотъемлемой частью текущего проекта разработки. Однако, например, небольшие программы, vue, react, weex и т. д. на самом деле имеют свой собственный или свой рекомендуемый набор API и соответствующие методы написания. Ни одна из них не написана по его рекомендации, на самом деле это очень больно и очень неудобно в использовании. Инкапсулируйте их API и предоставьте единый API, который удобнее использовать для себя или особенно для ваших товарищей по команде, что снижает стоимость повторного обучения, а также очень удобен единый формат, обеспечиваемый единым API.Большое преимущество.
Когда дело доходит до небольших программ, есть много вещей, которые нужно выяснить, и я все еще выясняю, как справиться с некоторыми ямами. Например, компонентизация небольших программ, использование глобальных переменных (какое значение можно поместить в app.js), преобразование html-тегов и т. д., я выйду и покажу свое безобразие позже.