Spark 请求海外Akamai接口

108 阅读3分钟

最近做的一个项目涉及到从Akamai海外接口获取数据并进行解析,这里记录一下请求的两种方式,根据不同情况使用不同的方式。

说明:Akamai接口的鉴权方式是用户需要先申请个人账户的鉴权信息,包括accesstoken、clienttoken、clientsecret、switchkey和host,用户请求接口时携带鉴权信息访问接口获取数据。

方式一:

Java版不需要代理情况下,程序所在的服务器可以直接请求海外接口。

主要maven依赖包括:

<dependencies>
    <dependency>
        <groupId>com.akamai.edgegrid</groupId>
        <artifactId>edgegrid-signer-apache-http-client</artifactId>
        <version>3.0.1</version>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.8</version>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>23.0</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.70</version>
    </dependency>
</dependencies>

首先生成客户端client,这里通过线程池来管理,避免每次请求都需要生成客户端造成资源浪费。

private PoolingHttpClientConnectionManager pool;
public AkAuth(){
    PoolingHttpClientConnectionManager pool=new PoolingHttpClientConnectionManager();
    pool.setMaxTotal(200);
    pool.setDefaultMaxPerRoute(100);
    this.pool=pool;
}

public HttpClient auth() {
    HttpClient client;
    try{
        ClientCredential credential = ClientCredential.builder()
                .host(host)
                .clientToken(token)
                .accessToken(key)
                .clientSecret(secret)
                .build();
        client = HttpClientBuilder.create()
                .addInterceptorFirst(new ApacheHttpClientEdgeGridInterceptor(credential))
                .setRoutePlanner(new ApacheHttpClientEdgeGridRoutePlanner(credential))
                .setConnectionManager(pool)
                .build();
    }catch (Exception e){
        throw new AuthException("认证异常",e);
    }
    return client;
}

接下来就是实际请求

protected String akamaiRequest(Account acc,String url,String query, DateTime start, DateTime end) {
    try {
        //获取client
        HttpClient client=akAuth.auth();
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
        //params值不编码也可以正常访问 通过账户id请求
        String pacc= URLEncoder.encode(acc.getId(),"UTF-8");
        //生成请求开始时间和结束时间
        String pstart= URLEncoder.encode(formatter.print(start),"UTF-8");
        String pend=URLEncoder.encode(formatter.print(end),"UTF-8");
        //请求参数填充到url中
        query=String.format(query,pacc,pstart,pend);
        HttpGet httpGet = new HttpGet(url+query);
        RequestConfig conf= RequestConfig.custom().setConnectTimeout(30000).setSocketTimeout(120000)
                .setConnectionRequestTimeout(60000).build();
        httpGet.setConfig(conf);
        HttpResponse response = client.execute(httpGet);
        String res = EntityUtils.toString(response.getEntity());
        int code=response.getStatusLine().getStatusCode();
        //返回状态码不为200则抛出异常
        Preconditions.checkState(200==code,String.format("API请求异常: %s,%s",code,res));
        return res;
    } catch (Exception e) {
        throw new ApiException("查询接口异常",e);
    }
}

方式二:

Scala版需要代理,一般用于内网,通过代理服务器转发请求进而请求海外接口。Maven依赖与方式一相同。

def akamaiRquest(url: String, switchKey: String, query: String,objectsid:String, start: String, end: String): String = try {
  //注 这里获取客户端没有通过线程池 也不直接携带鉴权信息
  var client = HttpClientBuilder.create().build()
  //参数填充到url中
  var querys = String.format(query, switchKey, start, end,objectsid)
  var httpGet = new HttpGet(url + querys)
  //设置代理服务器域名
  val header5 = new BasicHeader("xhost",proxyhost)
  var credential = ClientCredential.builder()
    .host(host)
    .clientToken(clientToken)
    .accessToken(accessToken)
    .clientSecret(clientSecret)
    .build()
  var body = new Array[Byte](0)
  var method = "GET"
  var uri = url+querys
  //生成request
  var request:Request = new RequestBuilder().body(body).headers(headers).method(method).uri(uri).build()
  //添加鉴权信息
  var authHeader = new EdgeGridV1Signer().getSignature(request,credential)
  //配置请求参数
  var conf = RequestConfig.custom().setConnectTimeout(30000).setSocketTimeout(120000).setConnectionRequestTimeout(60000).build()
  httpGet.setConfig(conf)
  httpGet.setHeader(header5)
  httpGet.setHeader("Authorization",authHeader)
  println(url+querys)
  var response = client.execute(httpGet)
  var res = EntityUtils.toString(response.getEntity)
  println(res)
  val code = response.getStatusLine.getStatusCode
  Preconditions.checkState(200==code,String.format("cd"))
  res
} catch {
  case e: Exception => throw new Exception("查询接口异常", e)
}

总结:两种请求方式使用的语言不同,故而代码结构略有不同,方式一使用了线程池,生成客户端的时候就进行了权限验证,后续请求数据即可,方式二则是考虑到要通过代理服务器转发请求将鉴权信息放在了请求头header中,验证发现如有代理必须将鉴权信息放在请求头中,不然类似于方式一无法通过鉴权,方式二也没有使用线程池,这一点还有待完善。