vue使用jsonp请求

Vue-jsonp

用于处理 vue 发送 JSONP 请求的轻量js库。

Install

npm install vue-jsonp -S

用法

    1. 在main.js中添加,注册为Vue的全局插件
import { VueJsonp } from 'vue-jsonp'
Vue.use(VueJsonp)

现在你可以在Vue的组件中使用 this.$jsonp 发送 jsonp 请求了,因为Vue.use(VueJsonp)里把 $jsonp 赋给 vue 原型了:Vue.prototype.$jsonp = jsonp
例如请求百度地图接口:

     this.$jsonp('https://apis.map.qq.com/ws/place/v1/suggestion', {
        region: "杭州",
        keyword: query,
        key: "CCWBZ-LZD6S-67COM-6GWDO-CHJ67-*****", 
        output: 'jsonp'
      }).then(res => {
        // ...
      })
    1. 在组件中直接使用函数:
      import { jsonp } from 'vue-jsonp'

      jsonp('https://apis.map.qq.com/ws/place/v1/suggestion', {
        region: "杭州",
        keyword: query,
        key: "CCWBZ-LZD6S-67COM-6GWDO-CHJ67-*****", 
        output: 'jsonp'
      }).then(res => {
        // ...
      })
  • 发送数据和设置查询参数 & 函数名
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&callback=jsonp_{RANDOM_STR}".
jsonp('/some-jsonp-url', {
  name: 'LancerComet',
  age: 100
})
  • 自定义查询和函数名
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&cb=jsonp_func".
jsonp('/some-jsonp-url', {
  callbackQuery: 'cb',
  callbackName: 'jsonp_func',
  name: 'LancerComet',
  age: 100
})

部分源码分析

image.png

vue-jsonp是使用rollupjs作为打包工具,采用typescript语法进行开发。入口文件./lib/index.ts 核心代码也就185行代码,挺精简了。

import Vue from 'vue'
import { PluginObject } from 'vue/types/plugin'
import { flatten, formatParams, randomStr } from './utils'

const DEFAULT_TIMEOUT: number = 5000

declare module 'vue/types/vue' {
  // tslint:disable-next-line:interface-name
  interface Vue {
    $jsonp: typeof jsonp
  }
}

/**
 * Vue JSONP.
 */
// tslint:disable-next-line:variable-name
const VueJsonp: PluginObject<never> = {
  install (V: typeof Vue) {
    V.prototype.$jsonp = jsonp
  }
}


// ....
export {
  VueJsonp,
  jsonp
}

在 TypeScript 中制作插件需要类型声明,项目中使用TypeScript 模块补充 (module augmentation)的特性,在declare module 'vue/types/vue' 中声明了 Vue 要补充的 $jsonp 类型,注册VueJsonp插件, 将$jsonp 赋给 vue 原型,将jsonp 函数挂载到Vue.prototype.$jsonp上。

const VueJsonp: PluginObject<never> = {
  install (V: typeof Vue) {
    V.prototype.$jsonp = jsonp
  }
}

jsonp()

  • jsonp函数就是动态创建了script标签,利用<script>的src不受同源策略约束来跨域获取数据
  • 在window对象上根据callbackName创建全局回调函数来接收数据,将请求地址拼接上请求参数,并挂载到document上,等服务端响应并返回约定的数据,返回一个promise实例, resolve(json)
  • JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
function jsonp<T = any> (
  url: string,
  param: IJsonpParam = {},
  timeout?: number
): Promise<T> {
  if (typeof url !== 'string') {
    throw new Error('[Vue-jsonp] Type of param "url" is not string.')
  }

  if (typeof param !== 'object' || !param) {
    throw new Error('[Vue-jsonp] Invalid params, should be an object.')
  }

  timeout = typeof timeout === 'number'
    ? timeout
    : DEFAULT_TIMEOUT

  return new Promise<T>((resolve, reject) => {
    const callbackQuery = typeof param.callbackQuery === 'string'
      ? param.callbackQuery
      : 'callback'
    const callbackName = typeof param.callbackName === 'string'
      ? param.callbackName
      : 'jsonp_' + randomStr()

    param[callbackQuery] = callbackName

    // Remove callbackQuery and callbackName.
    delete param.callbackQuery
    delete param.callbackName

    // Convert params to querying str.
    let queryStrs: (string[])[] = []
    Object.keys(param).forEach(queryKey => {
      queryStrs = queryStrs.concat(formatParams(queryKey, param[queryKey]))
    })

    const queryStr = flatten(queryStrs).join('&')

    const onError = () => {
      removeErrorListener()
      clearTimeout(timeoutTimer)
      reject({
        status: 400,
        statusText: 'Bad Request'
      })
    }

    const removeErrorListener = () => {
      paddingScript.removeEventListener('error', onError)
    }

    const removeScript = () => {
      document.body.removeChild(paddingScript)
      delete window[callbackName]
    }

    // Timeout timer.
    let timeoutTimer = null

    // Setup timeout.
    if (timeout > -1) {
      timeoutTimer = setTimeout(() => {
        removeErrorListener()
        removeScript()
        reject({
          statusText: 'Request Timeout',
          status: 408
        })
      }, timeout)
    }

    // Create global function.
    window[callbackName] = (json: T) => {
      clearTimeout(timeoutTimer)
      removeErrorListener()
      removeScript()
      resolve(json)
    }

    // Create script element.
    const paddingScript = document.createElement('script')

    // Add error listener.
    paddingScript.addEventListener('error', onError)

    // Append to head element.
    paddingScript.src = url + (/\?/.test(url) ? '&' : '?') + queryStr
    document.body.appendChild(paddingScript)
  })
}

参考资料

vue-jsonp - npm
vue-jsonp - github

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容