import { defaultValue, isNull, Log } from '../util'
import FetchRequest from './FetchRequest'
import RequestInterceptor from './RequestInterceptor'
import ResponseInterceptor from './ResponseInterceptor'
import { TokenAttachType } from '../base/enum'
import {
getWMSInfoFromXML,
getDoc,
getWMTSInfoFromXML,
getWFSInfoFromXML,
fromQueryResult,
getWFSFeature,
ServiceConfigToken,
ServiceConfigRequestInterceptors, ServiceConfigResponseInterceptors
} from './Utils'
import { FeatureSet } from '../base'
import { SpatialReference } from '../base/geometry'
import Config from './Config'
/**
* @private
* @class FetchServer
* @classdesc 对接各种服务的Service的基类。
* @param url - {string} 服务地址。
* @param options - {Object} 可选参数。如:
* @param {String} [options.url = 无] 基地址,必填
* @param {Object} [options.headers = 无] 自定义请求头参数
* @param {Function} [options.requestInterceptor = 无] 所有请求发送前会触发的函数
* @param {Function} [options.responseInterceptor = 无] 所有请求发送后会触发的函数
* @param {Number} [options.requestTimeout = 45000] 请求超时时间,默认45000ms,即45s
* @param {String} [options.tokenKey = 'token'] token名
* @param {String} [options.tokenValue = 无] token值
* @param {TokenAttachType} [options.tokenAttachType = TokenAttachType.url] 指定token附加到何处
*/
class FetchServer {
constructor(url, options) {
options = defaultValue(options, {})
/**
* 服务基地址
* @member {String} FetchServer.prototype.url
* */
this.url = url
/**
* 所有请求发送前会触发的函数
* @member {Function} FetchServer.prototype.requestInterceptor
* */
this.requestInterceptor = defaultValue(
options.requestInterceptor,
new RequestInterceptor()
)
/**
* 所有请求发送后会触发的函数
* @member {Function} FetchServer.prototype.responseInterceptor
* */
this.responseInterceptor = defaultValue(
options.responseInterceptor,
new ResponseInterceptor()
)
/**
* 请求超时时间,默认45000ms,即45s
* @member {Function} FetchServer.prototype.requestTimeout
* */
this.requestTimeout = defaultValue(options.requestTimeout, 45000)
/**
* 请求头参数
* @member {Function} FetchServer.prototype.headers
* */
this.headers = defaultValue(options.headers, {})
/**
* token名
* @member {Function} FetchServer.prototype.tokenKey
* */
this.tokenKey = defaultValue(options.tokenKey, 'token')
/**
* token值
* @member {Function} FetchServer.prototype.tokenValue
* */
this.tokenValue = defaultValue(options.tokenValue, undefined)
/**
* 指定token附加到何处
* @member {Function} FetchServer.prototype.tokenAttachType
* */
this.tokenAttachType = defaultValue(
options.tokenAttachType,
TokenAttachType.url
)
}
/**
* 销毁对象方法
* */
destroy() {
this.url = null
this.options = null
}
/**
* @function FetchServer.prototype.request
* @description: 该方法用于向服务发送请求。
* @param options - {Object} 参数。
* @param {string} [options.method] 请求方式,包括"GET","POST","PUT","DELETE"。
* @param {string} [options.url] 发送请求的地址。<br>
* @param {String} [options.data] 发送到服务器的数据,适用于"POST"。
* @param {Function} [options.success] 成功回调函数。
* @param {Function} [options.failure] 失败回调函数。
* @param {Boolean} [options.withCredentials = false] 是否携带cookie。
*/
request(options) {
options = defaultValue(options, {})
// url正确性检查
if (isNull(options.url)) {
Log.error('url不存在!')
return
}
// 执行所有请求发送前会触发的函数
if (
!isNull(this.requestInterceptor) &&
!isNull(this.requestInterceptor.before) &&
this.requestInterceptor.before instanceof Function
) {
options = this.requestInterceptor.before(options)
}
if (!isNull(options)) {
return this._commit(options)
}
}
_commit(options) {
const self = this
if (options.url.indexOf('?') > -1) {
if (options.url.indexOf('?') === options.url.length - 1) {
options.url += `${ServiceConfigToken(Config)}`
} else {
options.url += `&${ServiceConfigToken(Config)}`
}
} else {
if (options.method !== 'POST') {
options.url += `?${ServiceConfigToken(Config)}`
}
}
options.url = ServiceConfigRequestInterceptors(Config, options.url)
options.headers = defaultValue(options.headers, {})
let _headers = Object.assign(options.headers, this.headers)
_headers = Object.assign(_headers, Config.headers)
const _fetchOptions = {
headers: _headers,
withCredentials: options.withCredentials,
requestTimeout: this.requestTimeout,
proxy: options.proxy,
tokenKey: this.tokenKey,
tokenValue: this.tokenValue,
tokenAttachType: this.tokenAttachType
}
if (options.responseType) {
_fetchOptions.responseType = options.responseType
}
return FetchRequest.commit(
options.method,
options.url,
options.data,
_fetchOptions
)
.then(function (response) {
let check
if (response.text) {
if (_fetchOptions.responseType === 'blob') {
return response.blob()
} else {
check = () => response.text()
}
} else {
check = () => response.json()
}
if (response.status === 200) {
return new Promise(
(resolve) => {
check().then(function (text) {
let result
// 如果返回信息不存在
if (isNull(text)) {
result = {
succeed: true,
msg: '服务器没有返回信息',
data: undefined
}
} else {
let data
// 有返回信息,将text转为对象
if (typeof text === 'string') {
// 是xml,则解析
if (text.indexOf('<?xml') > -1) {
// 是WMS的元数据信息
if (
text.indexOf('OGC:WMS') > -1 ||
text.indexOf('WMS_Capabilities') > -1
) {
// 确认服务版本号
let version = '1.1.1'
if (text.indexOf('1.3.0') > -1) {
version = '1.3.0'
}
// xml转dom元素
const xmlDoc = getDoc(text)
// 从dom中获取信息
data = getWMSInfoFromXML(xmlDoc, version)
} else if (
text.indexOf('WMTS') > -1 ||
text.indexOf('wmts/1.0') > -1
) {
// 是WMTS的元数据信息
// xml转dom元素
const xmlDoc = getDoc(text)
// 从dom中获取信息
data = getWMTSInfoFromXML(xmlDoc)
}
// 取服务元信息
else if (text.indexOf('wfs:WFS_Capabilities') > -1) {
// 是WFS的元数据信息
// xml转dom元素
const xmlDoc = getDoc(text)
// 从dom中获取信息
data = getWFSInfoFromXML(xmlDoc)
}
// WFS要素查询
else if (text.indexOf('wfs:FeatureCollection') > -1) {
// 是WFS的元数据信息
// xml转dom元素
const xmlDoc = getDoc(text)
// 从dom中获取信息
data = getWFSFeature(xmlDoc)
} else if (text.indexOf('<svg') > -1) {
// 是svg,则直接返回
data = text
}
} else if (text.indexOf('html>') > -1) {
if (
!isNull(self.responseInterceptor) &&
!isNull(self.responseInterceptor.failure) &&
self.responseInterceptor.failure instanceof Function
) {
self.responseInterceptor.failure({
succeed: false,
msg: `服务器不支持${options.method}请求或其他错误`,
data: undefined,
errorType: 'unKnownError'
})
}
if (
!isNull(options.failure) &&
options.failure instanceof Function
) {
options.failure({
succeed: false,
msg: `服务器不支持${options.method}请求或其他错误`,
data: undefined,
errorType: 'unKnownError'
})
}
return Promise.reject({
succeed: false,
msg: `服务器不支持${options.method}请求或其他错误`,
data: undefined,
errorType: 'unKnownError'
})
} else {
data = JSON.parse(text)
// 基于矢量图层的要素查询,报数据转为feature
if (
data instanceof Object &&
(options.url.indexOf('/igs/rest/mrfs/layer/query') >
-1 ||
options.url.indexOf('/igs/rest/mrfs/docs/') > -1)
) {
// 可以进行多GDBP的要素查询,因此返回要素集合数组
const featureSets = fromQueryResult(data)
delete data.SFEleArray
data.featureSets = featureSets
// 返回要素信息数组
const featureInfos = []
if (featureSets.length > 1) {
for (let i = 0; i < featureSets.length; i++) {
featureInfos.push(data[String(i)])
delete data[String(i)]
}
} else {
data.AttStruct.TotalCount = data.TotalCount
featureInfos.push(data.AttStruct)
delete data.AttStruct
delete data.TotalCount
}
data.featureInfos = featureInfos
if (
options.url.indexOf('/igs/rest/mrfs/docs/') > -1 ||
options.url.indexOf('/igs/rest/mrfs/layer/') > -1
) {
if (featureSets.length > 0) {
data.featureSet = featureSets[0]
} else {
data.featureSet = new FeatureSet()
}
}
}
}
}
// 如果不是对象,直接返回信息
if (!(data instanceof Object)) {
result = {
succeed: true,
msg: data,
data
}
} else {
// 数据里面有features属性且为数组,且里面的是一个要素
if (
data.hasOwnProperty('features') &&
data.features instanceof Array
) {
// 解析服务内坐标信息
let spatialReference = new SpatialReference('EPSG:4326')
if (data.spatialReference) {
spatialReference = SpatialReference.fromJSON(
data.spatialReference
)
}
const reg = /(igs)\/rest\/services\/.*\/WFSServer/
let reverse = false
// 是否对数据反转
if (
reg.test(options.url) &&
spatialReference.wkid === 4326
) {
reverse = true
}
// 转成要素基本对象
data.featureSet = FeatureSet.fromArray(
data.features,
new FeatureSet({
spatialReference
}),
{
reverse
}
)
} else if (
options.url.indexOf('/MapServer/query') > -1 ||
options.url.indexOf('/SceneServer/query') > -1
) {
if (data.layers && data.layers instanceof Array) {
// 解析服务内坐标信息
let spatialReference = new SpatialReference('EPSG:4326')
if (data.spatialReference) {
spatialReference = new SpatialReference({
wkid: data.spatialReference.wkid,
wkt: data.spatialReference.wkt
})
}
const layers = data.layers
for (let i = 0; i < layers.length; i++) {
if (layers[i].features) {
layers[i].featureSet = FeatureSet.fromArray(
layers[i].features,
new FeatureSet({ spatialReference })
)
delete layers[i].features
}
}
}
}
// 查询图层列表信息
else if (options.url.indexOf('/MapServer/layers?') > -1) {
function _setLayersId(layers) {
for (let i = 0; i < layers.length; i++) {
layers[i].id = layers[i].index
if (
layers[i].children &&
layers[i].children instanceof Array
) {
_setLayersId(layers[i].children)
}
}
}
_setLayersId(data.layers)
}
result = {
succeed: true,
msg: '请求成功',
data
}
}
}
// 执行config的after方法
result = ServiceConfigResponseInterceptors(
Config,
options.url,
result
)
// 执行请求响应,接口调用成功时会执行的回调
if (
!isNull(self.responseInterceptor) &&
!isNull(self.responseInterceptor.success) &&
self.responseInterceptor.success instanceof Function
) {
result = self.responseInterceptor.success(result)
}
// 有成功回调函数,则执行
if (
!isNull(result) &&
!isNull(options.success) &&
options.success instanceof Function
) {
options.success(result)
}
resolve(result)
})
},
(reject) => {
console.log('Fetch返回异常', reject)
}
)
} else {
return new Promise(
(resolve) => {
check().then(function (text) {
let result
// 如果返回信息不存在,则返回请求失败
if (isNull(text)) {
result = {
succeed: false,
msg: '请求失败,服务器没有返回信息',
data: undefined
}
} else {
// 有返回信息,将text转为对象
const data = JSON.parse(text)
// 如果不是对象,直接返回信息
if (!(data instanceof Object)) {
result = {
succeed: false,
msg: data,
data: undefined
}
} else {
result = {
succeed: false,
msg: '请求失败',
data
}
}
}
// 请求响应成功,接口调用失败时会执行的函数
if (
!isNull(self.responseInterceptor) &&
!isNull(self.responseInterceptor.failure) &&
self.responseInterceptor.failure instanceof Function
) {
result = self.responseInterceptor.failure(result)
}
// 当failure回调存在,则运行failure
if (
!isNull(result) &&
!isNull(options.failure) &&
options.failure instanceof Function
) {
options.failure(result)
}
resolve(result)
})
},
(reject) => {
console.error('Fetch返回异常', reject)
}
)
}
})
.catch(function (error) {
// 执行所有请求发送失败后触发的函数
if (
!isNull(self.requestInterceptor) &&
!isNull(self.requestInterceptor.failure) &&
self.requestInterceptor.failure instanceof Function
) {
self.requestInterceptor.failure(error)
}
})
}
}
export default FetchServer